码迷,mamicode.com
首页 > 编程语言 > 详细

【LeetCode】数组

时间:2019-02-11 20:04:55      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:最小   年龄   多少   滑动   oba   break   play   longest   操作   

【1】Two Sum (2019年1月20日,review)

Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,

return [0, 1].

题解:我们可以用一个 map 存储 数组元素 和下标的关系。key 是 nums[i], value是 i。用一个循环遍历数组,然后在 map 中寻找 target - nums[i] 的值。(corner case 是如果这个数组有重复元素怎么办)。比如 [2, 3, 2, 4], target 是 4。 我们可以设计这么一个结构: map<int, vector<int>> 存储下标的数组。

技术图片
 1 //这种类似 hash 的能用 unordered_map 就不要用 map, hash-table + one pass
 2 class Solution {
 3 public:
 4     vector<int> twoSum(vector<int>& nums, int target) {
 5         const int n = nums.size();
 6         unordered_map<int, int> mp;
 7         vector<int> ans(2);
 8         for (int i = 0; i < n; ++i) {
 9             int key = target - nums[i];
10             if (mp.find(key) != mp.end()) {
11                 ans[0] = mp[key];
12                 ans[1] = i;
13                 break;
14             }
15             mp[nums[i]] = i;
16         }
17         return ans;
18     }
19 };
View Code

  

【4】Median of Two Sorted Arrays 

 

【11】Container With Most Water (2019年1月21日,复习)

给了一个数组,里面的值代表数字的高度,任意两根柱子中间可以蓄水,我们想知道蓄水的最大的矩形面积是多少。长度是两根柱子中短的那个,宽度是两根柱子的下标之差。

题解:一开始的想法 O(N^2) 暴力枚举所有的两根柱子, 但是显然可能不是这么想的 233。

后来 2 pointers,  O(N) 我们用 begin 和 end 指针指向两个最边缘的柱子。然后计算矩形的值。然后挑出一根比较小的柱子往中间平移这个指针。

这么做的原因是因为其实矩形面积的瓶颈在于那根比较小的柱子,我们尝试抛弃一下比较小的柱子,看能不能获得更大的值。

 如果两根柱子的高度一样长的话,那么随便抛弃任何一根都可以。因为如果往前移动的话,如果前面那根柱子的高度比现在的高度高的话,那么新的矩形面积是还是比原来矩形的小,因为没有移动的那侧的柱子就变成了新的矩形高度。如果前面那根柱子比现在高度矮的话,那么新的矩形面积肯定是比原来矩形面积小。e g. [6,7,5,6]

技术图片
 1 class Solution {
 2 public:
 3     int maxArea(vector<int>& height) {
 4         const int n = height.size();
 5         int begin = 0, end = n - 1;
 6         int ret = 0;
 7         while (begin < end) {
 8             int area = (end - begin) * min(height[begin], height[end]);
 9             ret = max(ret, area);
10             if (height[begin] > height[end]) {
11                 --end;
12             } else {
13                 ++begin;
14             }
15         }
16         return ret;
17     }
18 };
View Code

  

【15】3Sum 

 

【16】3Sum Closest 

 

【18】4Sum 

 

【26】Remove Duplicates from Sorted Array (2019年1月22日,复习)

有序数组去重,返回数组中的所有出现过的元素。

题解:2 pointers

技术图片
 1 class Solution {
 2 public:
 3     int removeDuplicates(vector<int>& nums) {
 4         const int n = nums.size();
 5         if (n == 0) {return n;}
 6         int idx = 1;
 7         for (int i = 1; i < n; ++i) {
 8             if (nums[i-1] != nums[i]) {
 9                 nums[idx++] = nums[i];
10             }
11         }
12         return idx;
13     }
14 };
View Code

 

【27】Remove Element (2018年10月31日,算法群)

给了一个数组 nums,和一个值 val,要求返回数组中不等于val的值,和这些值的个数。要求不能开辟新空间,只能原地修改数组。

题解:two pointers。 第一根指针指向新数组的值,第二根指针遍历原数组,如果第二根指针的值不等于 val,就把它赋值给新数组。时间复杂度 O(N),空间复杂度 O(1) 

技术图片
 1 class Solution {
 2 public:
 3     int removeElement(vector<int>& nums, int val) {
 4         const int n = nums.size();
 5         int idx = 0;
 6         for (int i = 0; i < n; ++i) {
 7             if (nums[i] != val) {
 8                 nums[idx++] = nums[i];
 9             }
10         }
11         return idx;
12     }
13 };
View Code

 

【31】Next Permutation (2019年1月20日,冲刺复习,求下一个排列)

找下一个排列(实现记不住用生日举例子,19930421,0的位置就是低位)

题解:(1)从后往前找第一个违反了递增顺序的元素,标记出来。(我们的目标是让这个数整体变大,所以我们要找到一个低的位置,让它变大)

(2)从后往前找第一个比标记元素更大的元素

(3)交换这两个数。

(4)从标记元素的后面一位开始翻转整个字符串。

技术图片
 1 class Solution {
 2 public:
 3     void nextPermutation(vector<int>& nums) {
 4         //1. right -> left, find the first digit which violate the increase trend;
 5         const int n = nums.size();
 6         int partitionIdx = -1;
 7         for (int i = n - 2; i >= 0; --i) {
 8             if (nums[i] < nums[i+1]) {
 9                 partitionIdx = i;
10                 break;
11             }
12         }
13         // if all the nums are in decrease trend, return reverse nums.
14         if (partitionIdx == -1) {
15             reverse(nums.begin(), nums.end());
16             return;
17         }
18         //cout << "partitionIdx:" << partitionIdx << endl;
19         //2. right -> left, find change number, which is the first digit larger than partition number;
20         int changeIdx = 0;
21         for (int i = n - 1; i >= 0; --i) {
22             if (nums[i] > nums[partitionIdx]) {
23                 changeIdx = i;
24                 break;
25             }
26         }
27         //3. swap partition number and change number
28         swap(nums[partitionIdx], nums[changeIdx]);
29         
30         //4. reverse all the digit on the right of partition idx
31         //partitionIdx = changeIdx;
32         reverse(nums.begin() + partitionIdx + 1, nums.end());
33         
34         return;
35     }
36 };
View Code

可以变种成找 pre_permutation

我们的目标是让数变小,所以我们要找一个高位,让它变小,其他和next_permutation一样。

 

【33】Search in Rotated Sorted Array (2018年10月28日,算法群)

在一个旋转数组中查找一个值 target,旋转数组没有重复数字,如果 target 存在,返回下标,否则返回 -1. 时间复杂度要求 O(logN)

题解:二分。重点是不要写的有bug,我对旋转数组这种题都是写的左闭右闭区间。

技术图片
 1 class Solution {
 2 public:
 3     int search(vector<int>& nums, int target) {
 4         int left = 0, right = nums.size()-1;
 5         while (left <= right) {
 6             int mid = (left + right) / 2;
 7             if (nums[mid] == target) {
 8                 return mid;
 9             }else if (nums[mid] < target) { //找一个比 nums[mid] 大的数
10                 if (nums[mid] < nums[right]) { //转折点在 mid 左边
11                     if (target <= nums[right]) { // target就在右边
12                         left = mid + 1;
13                     } else {
14                         right = mid - 1; // target在左边
15                     }
16                 } else { //转折点在 mid 右边
17                     left = mid + 1; 
18                 }
19             } else { // 找一个比 nums[mid] 小的数
20                 if (nums[mid] < nums[right]) { //转折点在 mid 左边
21                     right = mid - 1;
22                 } else { //转折点在 mid 右边
23                     if (target <= nums[right]) {
24                         left = mid + 1;
25                     } else {
26                         right = mid -1;
27                     }
28                 }
29             }
30         }
31         return -1;
32     }
33 };
View Code

 

【34】Find First and Last Position of Element in Sorted Array 

【35】Search Insert Position 

【39】Combination Sum 

【40】Combination Sum II 

 

【41】First Missing Positive (2019年1月23日,谷歌复习) (H)

给了一个数组里面有正数和负数,返回第一个没有出现的正整数。要求了时间复杂度是 O(N)

Given an unsorted integer array, find the smallest missing positive integer.

Example 1:

Input: [1,2,0]
Output: 3 

Example 2:

Input: [3,4,-1,1]
Output: 2

Example 3:

Input: [7,8,9,11,12]
Output: 1

题解:这个题用 bucketsort, 先排序(bucket sort这个题怎么排序是个重点),把 i 位置的元素尽量放成 i + 1,然后依次比较 nums[i] 是否是 i + 1 就行了。

技术图片
 1 class Solution {
 2 public:
 3     int firstMissingPositive(vector<int>& nums) {
 4         const int n = nums.size();
 5         bucketsort(nums);
 6         for (int i = 0; i < n; ++i) {
 7             if (nums[i] != i+1) {
 8                 return i+1;
 9             }
10         }
11         return n + 1;
12     }
13     void bucketsort(vector<int>& nums) {
14         const int n = nums.size();
15         for (int i = 0; i < n; ++i) {
16             while (nums[i] != i+1) {
17                 if (nums[i] <= 0 || nums[i] > n || nums[i] == nums[nums[i]-1]) {
18                     break;
19                 }
20                 swap(nums[i], nums[nums[i]-1]);   
21             }
22         }
23         return;
24     }
25 };
View Code

 

【42】Trapping Rain Water (2019年1月23日,谷歌复习) (H)

技术图片

题解:单调栈。

技术图片
 1 class Solution {
 2 public:
 3     int trap(vector<int>& height) {
 4         const int n = height.size();
 5         int ret = 0;
 6         stack<int> stk;
 7         for (int i = 0; i < n; ++i) {
 8             while (!stk.empty() && height[i] > height[stk.top()]) {
 9                 int preIdx = stk.top(); stk.pop();
10                 if (stk.empty()) {break;}
11                 int leftIdx = stk.top();
12                 int width = i - leftIdx -1, h = min(height[i], height[leftIdx]) - height[preIdx];
13                 ret += width * h;
14             }
15             stk.push(i);
16         }
17         return ret;
18     }
19 };
View Code

 

【45】Jump Game II (2019年1月23日,谷歌复习) (H)

Given an array of non-negative integers, you are initially positioned at the first index of the array. 

Each element in the array represents your maximum jump length at that position.

Your goal is to reach the last index in the minimum number of jumps.

Example:

Input: [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
    Jump 1 step from index 0 to 1, then 3 steps to the last index.

 题解:BFS 最后一个 case 超时。要用贪心解法。贪心的意思是说,维护一个左右的区间,然后遍历左右区间的值,去试探下个区间的右边界的最大值,更新。然后滑动这个区间窗口。到新的区间。

技术图片
 1 class Solution {
 2 public:
 3     int jump(vector<int>& nums) {
 4         int left = 0, right = 0, step = 0;
 5         while (right < nums.size() - 1) {
 6             int next_r = right;
 7             for (int i = left; i <= right; ++i) {
 8                 next_r = max(next_r, i + nums[i]);
 9             } 
10             left = right;
11             right = next_r;
12             ++step;
13         }
14         return step ;
15     }
16 };
View Code

 

【48】Rotate Image (2019年1月20日,谷歌决战复习)

给了一个正方形的矩阵 N * N, 原地顺时针旋转 90度,返回旋转后的矩阵。

题解:按照程序员代码面试指南中的题解,这个题也能按照矩阵分圈处理的方式进行。我们用四个变量,tr, tc, dr, dc 来标记位置一个 entry 的位置。然后四个 entry 为一组,一个 M * M 的圈有 M-1 组。每组组内元素交换。

技术图片
 1 //答案参考了程序员代码面试指南,第八章,正方形矩阵顺时针旋转90度
 2 class Solution {
 3 public:
 4     void rotate(vector<vector<int>>& matrix) {
 5         const int n = matrix.size()-1;
 6         int tr = 0, dr = n, tc = 0, dc = n;
 7         while (tr < dr) {
 8             rotateEdge(matrix, tr++, dr--, tc++, dc--);
 9         }
10         return;
11     }
12     void rotateEdge(vector<vector<int>>& matrix, int tr, int dr, int tc, int dc) {
13         int group = dr - tr;
14         for (int i = 0; i < group; ++i) {
15             int temp = matrix[tr][tc+i];
16             matrix[tr][tc+i] = matrix[dr-i][tc];
17             matrix[dr-i][tc] = matrix[dr][dc-i];
18             matrix[dr][dc-i] = matrix[tr+i][dc];
19             matrix[tr+i][dc] = temp;
20         }
21         return;
22     }
23 };
View Code

 

【53】Maximum Subarray (2019年1月23日,谷歌复习) 

最大子段和。

这个题后面要求还要用 divide and conquer做。

 

【54】Spiral Matrix (2019年1月23日,谷歌复习) 

矩阵分圈打印。用四个变量一圈一圈打印就ok了。

 

【55】Jump Game 

【56】Merge Intervals 

【57】Insert Interval 

【59】Spiral Matrix II 

【62】Unique Paths 

【63】Unique Paths II 

【64】Minimum Path Sum 

【66】Plus One 

 

【73】Set Matrix Zeroes (2018年12月17日,算法群,第一遍rewiew,最优解没有想到)

给了一个 N*M 的矩阵matrix,如果里面有个元素为0,就把那个元素所在行和所在列的所有元素都标记为0,返回新数组。

题目要求空间复杂度为 O(1)

题解:我一开始只想出了 O(N+M)  的空间复杂度。想要 O(1) 的话,就要让原来数组的第0行和第0列充当我的O(N+M)的空间,然后用两个变量标记第0行和第0列是不是应该设置为0。

技术图片
 1 //本题我最多优化成O(N+M)的空间复杂度,优化成常量空间可以利用第0行和第0列。如果这行或者这列需要标记成0,那么在标记这行或者这列的第0个元素为0.
 2 //为了标记原数组的第0行或者第0列是不是应该标记为0,我们使用了两个变量来标记。
 3 class Solution {
 4 public:
 5     void setZeroes(vector<vector<int>>& matrix) {
 6         const int n = matrix.size(), m = matrix[0].size();
 7         bool setCol0 = false, setRow0 = false;
 8         //1. 先看第0行是否需要标记成0
 9         for (int j = 0; j < m; ++j) {
10             if (matrix[0][j] == 0) {
11                 setRow0 = true;
12             }
13         }
14         //2. 遍历矩阵标记每行每列的第0个元素
15         for (int i = 0; i < n; ++i) {
16             //看第0列是否需要标记为0.
17             if (matrix[i][0] == 0) {
18                 setCol0 = true;
19             }
20             for (int j = 0; j < m; ++j) {
21                 if (matrix[i][j] == 0) {
22                     matrix[i][0] = matrix[0][j] = 0;
23                 }
24             }
25         }
26         //3. 根据标记出来的,set0
27         for (int i = 1; i < n; ++i) {
28             for (int j = 1; j < m; ++j) {
29                 if (!matrix[i][0] || !matrix[0][j]) {
30                     matrix[i][j] = 0;
31                 }
32             }
33         }
34         //4. 看是否需要把第0行和第0列set为0
35         if (setRow0) {
36             for (int j = 0; j < m; ++j) {
37                 matrix[0][j] = 0;
38             }
39         }
40         if (setCol0) {
41             for (int i = 0; i < n; ++i) {
42                 matrix[i][0] = 0;
43             }
44         }
45         return;
46     }
47 };
View Code

 

【74】Search a 2D Matrix 

【75】Sort Colors (荷兰国旗问题,3-way partition)

【78】Subsets (2018年11月21日补充,同90题)

给了一个 distinct 的数组,返回它所有的子集。

题解可以看 bit manipulation 专题:https://www.cnblogs.com/zhangwanying/p/9886589.html(这题我更喜欢用 backtracking 解)

【79】Word Search 

【80】Remove Duplicates from Sorted Array II 

【81】Search in Rotated Sorted Array II 

【84】Largest Rectangle in Histogram 

【85】Maximal Rectangle 

【88】Merge Sorted Array 

【90】Subsets II (2018年11月21日,算法群)

给了一个有重复数字的数组,返回它所有的unique子集。

题解见 backtracking 专题,https://www.cnblogs.com/zhangwanying/p/9886305.html 

【105】Construct Binary Tree from Preorder and Inorder Traversal 

【106】Construct Binary Tree from Inorder and Postorder Traversal 

【118】Pascal‘s Triangle 

【119】Pascal‘s Triangle II 

【120】Triangle 

【121】Best Time to Buy and Sell Stock 

【122】Best Time to Buy and Sell Stock II 

【123】Best Time to Buy and Sell Stock III 

【126】Word Ladder II 

 

【128】Longest Consecutive Sequence (2018年11月22日,开始解决hard题)

给了一个无序的数组,问这个数组里面的元素(可以重新排序)能组成的最长的连续子序列是多长。本题的时间复杂度要求是 O(N).

Example:
Input: [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.

题解:我一开始想的是直接 sort 一下,然后用一根指针遍历应该就ok了,但是时间复杂度不满足。看了 solution,只看了标题说用 hashmap 存,就往那边想了一下。我是用了一个 unordered_map key是每个元素,value是从这个元素开始的连续子序列的长度。遍历一下数组,发现有直接跳跃加,虽然 for 里面有个 while,其实是 O(N)的,因为数组中的每个元素最多被访问了一次。beats 66%, 可以看下discuss里面优秀的解法。

技术图片
 1 //这道题需要 O(N) 的解法。尴尬。
 2 class Solution {
 3 public:
 4     int longestConsecutive(vector<int>& nums) {
 5         unordered_map<int, int> mp; //minn -> cnt
 6         for (auto e : nums) {
 7             mp[e] = 1;
 8         }
 9         int ret = nums.empty() ? 0 : 1;
10         for (auto e : nums) {
11             int target = e + mp[e];
12             while (mp.find(target) != mp.end()) {
13                 mp[e] += mp[target];
14                 ret = max(ret, mp[e]);
15                 target = e + mp[e];
16             }
17         }
18         return ret;
19     }
20 };
View Code

我看还有一个标签是 union-find,不会解,可以看看别人解法。

 

【152】Maximum Product Subarray 

【153】Find Minimum in Rotated Sorted Array 

【154】Find Minimum in Rotated Sorted Array II 

【162】Find Peak Element 

【163】Missing Ranges 

【167】Two Sum II - Input array is sorted 

 

【169】Majority Element 

给出一个非空的无序数组,长度为n,有一个数出现的次数超过了n/2,要求在O(1)的空间复杂度,O(n)的时间复杂度里面求出这个数字。

题解:原本想用map。复杂度不满足。

题解参考剑指offer面试题29。数组中有一个数字的个数超过数组长度的一半,说明它的出现次数要比其他所有数字出现的次数的和还要多。

因此我们可以考虑在遍历的时候保存两个值,一个是数组中的一个数字,一个是它出现的次数,当我们遍历到下一个数字的时候,相同则加一,不同则减一。如果次数为0,我们需要保存下一个数字,并且把次数设置为1.

技术图片
 1 //解答参考剑指offer,面试题29.
 2 //解法的原理是:数组中有一个数字的个数超过数组长度的一半,说明它的出现次数要比其他所有数字出现的次数的和还要多。y
 3 //因此我们可以考虑在遍历的时候保存两个值,一个是数组中的一个数字,一个是它出现的次数,当我们遍历到下一个数字的时候,相同则加一,不同则减一。如果次数为0,我们需要保存下一个数字,并且把次数设置为1.
 4 
 5 class Solution {
 6 public:
 7     int majorityElement(vector<int>& nums) {
 8         const int n = nums.size();
 9         int cnt = 0, number;
10         for (auto ele : nums) {
11             if (cnt == 0) {
12                 number = ele;
13             }
14             if (number == ele) {
15                 cnt += 1;
16             } else {
17                 cnt -= 1;
18             }
19         }
20         return number;
21     }
22 };
View Code

 

【189】Rotate Array 

【209】Minimum Size Subarray Sum 

【216】Combination Sum III 

【217】Contains Duplicate 

【219】Contains Duplicate II 

【228】Summary Ranges 

【229】Majority Element II 

 

【238】Product of Array Except Self (2018年12月25日,算法群)

给了一个数组nums,在不用除法的前提下,获取这个数组每个元素出了自己之外其他元素的乘积。要求除了返回的数组之外,常量空间复杂度。

题解:我们一开始可以设置两个数组,left[],right[] 记录每个元素左侧/右侧的乘积。然后把两个数组对应元素相乘就是结果数组。常量个空间复杂度可以继续优化 left,right数组,把这两个优化成两个变量。 

技术图片
 1 class Solution {
 2 public:
 3     vector<int> productExceptSelf(vector<int>& nums) {
 4         const int n = nums.size();
 5         int fromLeft = 1, fromRight = 1;
 6         vector<int> ret(n, 1);
 7         for (int i = 0; i < n; ++i) {
 8             ret[i] *= fromLeft;
 9             fromLeft *= nums[i];
10         }
11         for (int i = n-1; i >= 0; --i) {
12             ret[i] *= fromRight;
13             fromRight *= nums[i];
14         }
15         return ret;
16     }
17 };
View Code

 

【243】Shortest Word Distance 

【245】Shortest Word Distance III 

【259】3Sum Smaller 

【268】Missing Number 

【277】Find the Celebrity 

【280】Wiggle Sort 

【283】Move Zeroes 

【287】Find the Duplicate Number 

【289】Game of Life (2019年2月11日,谷歌tag)

给了一个2D grid,元素只有0,1,0代表died,1代表live。下一轮的state由本轮的该元素的八个邻居决定。有几条规则。问下轮所有元素的状态。规则如下:

 

  1. Any live cell with fewer than two live neighbors dies, as if caused by under-population.
  2. Any live cell with two or three live neighbors lives on to the next generation.
  3. Any live cell with more than three live neighbors dies, as if by over-population..
  4. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

 

本题要求不要新开数组,space complexity 是O(1)。

题解:拓展状态从0,1,(1bit表示状态)变成2 bit 表示状态,比如00, 01,10,11 (第一个bit代表原来的状态,第二个bit代表新状态)。

技术图片
 1 class Solution {
 2 public:
 3     void gameOfLife(vector<vector<int>>& board) {
 4         if (board.empty() || board[0].empty()) {return;}
 5         const int n = board.size(), m = board[0].size();
 6         const int dirx[8] = {-1, -1, -1, 1, 1, 1, 0, 0};
 7         const int diry[8] = {-1, 1, 0, -1, 1, 0, -1, 1};
 8         for (int i = 0; i < n; ++i) {
 9             for (int j = 0; j < m; ++j) {
10                 int cnt = 0; // count for lives
11                 for (int k = 0; k < 8; ++k) {
12                     int newx = i + dirx[k], newy = j + diry[k];
13                     if (newx < 0 || newx >= n || newy < 0 || newy >= m) { continue; }
14                     int oldState = board[newx][newy];
15                     if (newx < i || (newx == i && newy < j)) {
16                         oldState = board[newx][newy] >> 1;
17                     }
18                     if (oldState == 1) {cnt++;}
19                 }
20                 board[i][j] = (board[i][j] << 1) + getNewState(cnt, board[i][j]);
21             }
22         }
23         for (int i = 0; i < n; ++i) {
24             for (int j = 0; j < m; ++j) {
25                 board[i][j] %= 2;
26             }
27         }
28         return;
29     }
30     int getNewState(int liveNumbers, int oldState) {
31         if (oldState == 0) {
32             if (liveNumbers == 3) {return 1;}
33             else {return 0;}
34         }
35         if (liveNumbers < 2 || liveNumbers > 3) {return 0;}
36         return 1;
37     }
38 };
View Code

Follow up:

  1. Could you solve it in-place? Remember that the board needs to be updated at the same time: You cannot update some cells first and then use their updated values to update other cells. (题解的做法)
  2. In this question, we represent the board using a 2D array. In principle, the board is infinite, which would cause problems when the active area encroaches the border of the array. How would you address these problems?

解法:https://segmentfault.com/a/1190000003819277

 

【370】Range Addition (2019年1月29日,算法群打卡题)

实现一个区间加。给了一个原数组和一个区间修改的三元组,[startIdx, endIdx, inc] 代表在 [startIdx, endIdx]这个区间内每个元素都增加了 inc。求变换后的数组。

题解:差分+前缀和,差分数组记录区间的该变量,输入是 [l, r, inc] 的话,输出就是 arr[l] + inc, arr[r+1] - inc。把差分数组 arr 求前缀和之后,就能得到原数组每个位置的改变量。

技术图片
 1 //实现一个简单的区间加。差分数组每个位置记录这个区间的改变量,把差分数组求了前缀和就能求出每个位置的改变量。
 2 class Solution {
 3 public:
 4     vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {
 5         vector<int> res(length+1, 0);
 6         for (auto& update : updates) {
 7             int l = update[0], r = update[1], diff = update[2];
 8             res[l] += diff, res[r+1] -= diff;
 9         }
10         for (int i = 0; i < length; ++i) {
11             res[i+1] = res[i] + res[i+1];
12         }
13         res.resize(length);
14         return res;
15     }
16 };
View Code

 

【380】Insert Delete GetRandom O(1) 

【381】Insert Delete GetRandom O(1) - Duplicates allowed 

【414】Third Maximum Number 

【442】Find All Duplicates in an Array 

 

【448】Find All Numbers Disappeared in an Array (2019年2月11日)

一个数组中包含 n 个数,在 [1, n] 区间之内,有些数出现了一次,有些数出现了两次,返回一个列表,里面包含了所有没有出现过的数字。时间复杂度要求O(N), 空间复杂度是 O(1)

题解:我们想把数组中的第 i 个位置上的元素放 i + 1,这样排序之后遍历一遍数组即可。

 

技术图片
 1 class Solution {
 2 public:
 3     vector<int> findDisappearedNumbers(vector<int>& nums) {
 4         const int n = nums.size();
 5         for (int i = 0; i < n; ++i) {
 6             while (nums[i] != i + 1 && nums[i] != nums[nums[i]-1]) {
 7                 swap(nums[i], nums[nums[i]-1]);
 8             }
 9         }
10         vector<int> ret;
11         for (int i = 0; i < n; ++i) {
12             if (nums[i] != i + 1) {
13                 ret.push_back(i+1);
14             }
15         }
16         return ret;
17     }
18 };
View Code

 

 

 

【485】Max Consecutive Ones 

 

【495】Teemo Attacking 

Teemo攻击Ashe有一个攻击持续时间duration,题目中给了一个递增的数组,表示Teemo攻击的时间点,问Teemo的攻击总时间为多少。

题解:用个变量直接进行计算就ok。时间复杂度O(N), 空间复杂度O(1).

技术图片
 1 class Solution {
 2 public:
 3     int findPoisonedDuration(vector<int>& timeSeries, int duration) {
 4         const int n = timeSeries.size();
 5         if (n == 0) { return 0; }
 6         int ans = 0;
 7         int lastEnd = 0;
 8         for (int i = 0; i < n; ++i) {
 9             int start = timeSeries[i];
10             if (start < lastEnd) {
11                 ans += start + duration - lastEnd;
12             } else {
13                 ans += duration;
14             }
15             lastEnd = start + duration;
16         }
17         return ans;
18     }
19 };
View Code

 

【531】Lonely Pixel I 

给了一个用黑白("B", "W")表示的二维矩阵,输出lonely black的个数。 lonely black的定义为同一行同一列只能有一个 “B”。

题解:先用两个数组表示每行有几个“B”和每列有几个“B”,然后找下满足条件的。时间复杂度O(n^2), 空间复杂度O(n+m)。

技术图片
 1 class Solution {
 2 public:
 3     int findLonelyPixel(vector<vector<char>>& picture) {
 4         // 分别计算每行有几个B
 5         const int n = picture.size();
 6         if (n == 0) { return 0; }
 7         const int m = picture[0].size();
 8         if (m == 0) { return 0; }
 9         
10         vector<int> col(m, 0);
11         vector<int> row(n, 0);
12         
13         for (int i = 0; i < n; ++i) {
14             for (int j = 0; j < m; ++j) {
15                 row[i] += picture[i][j] == B ? 1 : 0;
16                 col[j] += picture[i][j] == B ? 1 : 0;
17             }
18         }
19         
20         int ans = 0;
21         for (int i = 0; i < n; ++i) {
22             if (row[i] == 1) {
23                 for (int j = 0; j < m; ++j) {
24                     if (picture[i][j] == B && col[j] == 1) {
25                         ans++;
26                     }
27                 }
28             }
29         }
30         return ans;
31     }
32 };
View Code

 

【532】K-diff Pairs in an Array 

给了一个数组,和一个整数k,问这个数组中有多少个pair的差的绝对值为k。所求的pair要求unique。

题解:先排序,然后双指针,因为pair要unique, 所以要用个set存.

时间复杂度O(nlogn), 空间复杂度O(n)

 

技术图片
 1 class Solution {
 2 public:
 3     int findPairs(vector<int>& nums, int k) {
 4         const int n = nums.size();
 5         if (n == 0 || n == 1) {
 6             return 0;
 7         }
 8         sort(nums.begin(), nums.end());
 9         int ans = 0;
10         int slow = 0, fast = 1;
11         set<pair<int, int>> st;
12         while (fast <= n -1 && fast > slow) {
13             if (nums[fast] - nums[slow] == k) {
14                 st.insert(make_pair(nums[slow], nums[fast]));
15                 fast++, slow++;
16             }
17             if (nums[fast] - nums[slow] < k) {
18                 fast++;
19             }
20             if (nums[fast] - nums[slow] > k) {
21                 slow++;
22                 if (fast == slow && fast < n - 1) {
23                     fast++;
24                 }
25             }
26         }
27         return st.size();
28     }
29 };
View Code

 

【533】Lonely Pixel II 

给了一个黑白矩阵,和一个整数N,求满足条件的黑点的个数。

条件1:黑点所在的行R,和所在的列C都必须有N个黑点。

条件2:对于所有在列C有黑点的行,都必须和行R相同。

题解:直接求,实现题。

技术图片
 1 class Solution {
 2 public:
 3     
 4     bool checkEqual(vector<vector<char>>&picture, int R, int i) {
 5         for (int m = 0; m < picture[0].size(); ++m) {
 6             if (picture[R][m] != picture[i][m]) {
 7                 return false;
 8             }
 9         }
10         return true;
11     }
12     
13     int findBlackPixel(vector<vector<char>>& picture, int N) {
14         const int n = picture.size();
15         if (n == 0) { return 0; }
16         const int m = picture[0].size();
17         if (m == 0) { return 0; }
18         
19         vector<int> row(n, 0);
20         vector<int> col(m, 0);
21         for (int i = 0; i < n; ++i) {
22             for (int j = 0; j < m; ++j) {
23                 row[i] += picture[i][j] == B ? 1 : 0;
24                 col[j] += picture[i][j] == B? 1 : 0;         
25             }
26         }
27         
28         vector<pair<int, int>> rc;
29         vector<int> r, c;
30         for (int i = 0; i < n; ++i) {
31             if (row[i] == N) {
32                 r.push_back(i);
33             }
34         }
35         for (int i = 0; i < m; ++i) {
36             if (col[i] == N) {
37                 c.push_back(i);
38             }
39         }
40         
41         for (auto e1 : r) {
42             for (auto e2 : c) {
43                 if (picture[e1][e2] == B)
44                     rc.push_back(make_pair(e1, e2));
45             }
46         }
47         
48         vector<pair<int, int>> ans;
49         for (auto ele : rc) {
50             int R = ele.first, C = ele.second;
51             bool check = true;
52             for (int i = 0; i < n; ++i) {
53                 if (i != R && picture[i][C] == B) {
54                     check = check & checkEqual(picture, R, i);
55                 }
56             }
57             if (check) {
58                 ans.push_back(ele);
59             }
60         }
61         
62         return ans.size();
63     }
64 };
View Code

 

【548】Split Array with Equal Sum 

 

 

【560】Subarray Sum Equals K 

给了一个数组和一个整数K,求所有和为K的子数组的个数。

题解:前缀和直接求,discuss里面有人有hash优化到了O(n).

前缀和的时间复杂度是O(n^2), 空间复杂度是O(n)

技术图片
 1 class Solution {
 2 public:
 3     int subarraySum(vector<int>& nums, int k) {
 4         const int n = nums.size();
 5         if (n == 0) {
 6             return 0;
 7         }
 8         int ans = 0;
 9         vector<int> s(n+1, 0);
10         for (int i = 1; i < n + 1; ++i) {
11             s[i] = s[i-1] + nums[i-1];
12         }
13         
14         for (int i = 0; i < n +1; ++i) {
15             for (int j = i + 1; j < n + 1; ++j) {
16                 int diff = s[j] - s[i];
17                 ans += diff == k ? 1 : 0;
18             }
19         }
20         return ans;
21     }
22 };
View Code

2018年10月28日(周日)更新,今天北邮的同学做了这道题来跟我讲hashmap的解法。时间复杂度可以优化到 O(N)

先求前缀和,然后 我们需要满足这么一个等式, summ[j] - summ[i] = K,移动一下左右两边,变成 summ[i] = summ[j] - K,我们的目标就是对于每个 j 都找到对应 summ[i] 的个数。于是我们用一个hashmap存已经遍历过的 summ[j] 的次数。

这边注意 hashmap 是随着 j 的遍历实时更新的,不然如果提前算出一个 hashmap, 可能存在 这么一个 summ[k] = summ[i] (k > j),但是这样的 j 和 k 是不能构成子数组的。

技术图片
 1 //2018年10月28日,和北邮小姐姐微信讨论这道题.
 2 //我以前是直接前缀和暴力求解了。现在用了 hashmap, 直接把时间复杂度降低成了 O(N).
 3 class Solution {
 4 public:
 5     int subarraySum(vector<int>& nums, int k) {
 6         const int n = nums.size();
 7         vector<int> summ(n+1, 0);
 8         map<int, int> cnt;
 9         cnt[0] = 1;
10         for (int i = 1; i < n + 1; ++i) {
11             summ[i] = summ[i-1] + nums[i-1];
12         }
13         int ans = 0;
14         for (int j = 1; j < n + 1; ++j) {
15             int key = summ[j] - k;
16             ans += cnt[key];
17             cnt[summ[j]]++; 
18             //hashmap是实时更新的,如果不实时更新,可能会存在一个 summ[k] = key, 但是 k > j, 这种不能当成数组但是又占个数的东西不能要
19         }
20         return ans;
21         
22     }
23 };
View Code

 

【561】Array Partition I 

 

【562】Longest Line of Consecutive One in Matrix 

给了一个01矩阵M, 求M的一条线中(行,列,正反对角线)最长1的长度。

题解:直接遍历求,时间复杂度O(n^2*x),空间复杂度O(1) 

这道题discuss里面有写可以dp求,时间复杂度会降下来。我直接暴力了。

技术图片
 1 class Solution {
 2 public:
 3     int longestLine(vector<vector<int>>& M) {
 4         const int n = M.size();
 5         if (n == 0) {return 0;}
 6         const int m = M[0].size();
 7         if (m == 0) {return 0;}
 8         int ans = 0;
 9         //1. cal rows
10         int localMax = 0;
11         for (int i = 0; i < n; ++i) {
12             int ptr = 0, temp = 0;
13             while (ptr < m) {
14                 if(M[i][ptr] == 1) {
15                     temp++;
16                 } else {
17                     localMax = max(localMax, temp);
18                     temp = 0;
19                 }
20                 ++ptr;
21             }
22             localMax = max(localMax, temp);
23         }
24         //printf("after cal rows, localMax = %d \n", localMax);
25         
26         
27         //2. cal cols
28         for (int j = 0; j < m; ++j) {
29             int ptr = 0, temp = 0;
30             while (ptr < n) {
31                 if (M[ptr][j] == 1) {
32                     temp++;
33                 } else {
34                     localMax = max(localMax, temp);
35                     temp = 0;
36                 }
37                 ++ptr;
38             }
39             localMax = max(localMax, temp);
40         }
41         //printf("after cal cols, localMax = %d \n", localMax);
42         
43         //3. cal diagonal && anti-diagonal
44         for (int i = 0; i < n ; ++i) {
45             for (int j = 0; j < m; ++j) {
46                 //diagonal
47                 int x = i, y = j;
48                 int temp = 0;
49                 while (x >= 0 && x < n && y >= 0 && y < m && M[x][y] == 1) {
50                     if (i - 1 >= 0 && i - 1< n && j - 1 >= 0 && j - 1 < m && M[i-1][j-1]) {
51                         break;
52                     }
53                     temp++;
54                     x++, y++;
55                 }
56                 //printf("diagonal: i = %d, j = %d, temp = %d \n", i, j, temp);
57                 localMax = max(localMax, temp);
58                 //anti-diagonal
59                 x = i, y = j;
60                 temp = 0;
61                 while (x >= 0 && x < n && y >= 0 && y < m && M[x][y] == 1) {
62                     if (i + 1 >= 0 && i + 1< n && j - 1 >= 0 && j - 1 < m && M[i+1][j-1]) {
63                         break;
64                     }
65                     temp++;
66                     x--, y++;
67                 }
68                 //printf("anti-diagonal: i = %d, j = %d, temp = %d \n", i, j, temp);
69                 localMax = max(localMax, temp);
70             }
71         }
72         
73         ans = localMax;
74         return ans;
75     }
76 };
View Code

 

【565】Array Nesting 

给了一个N个元素的数组,里面元素是0~N-1。数组有些元素的下标和元素的值形成了一个环,问环的最大长度。

题解:直接并查集做了,代码里还有个点需要考虑清楚。

技术图片
 1 class Solution {
 2 public:
 3     int findfa(int x, vector<int>& fa) {
 4         return x == fa[x] ? x : fa[x] = findfa(fa[x], fa);
 5     }
 6     void unionSet(int son, int father, vector<int>& fa) {
 7         int xx = findfa(son, fa), yy = findfa(father, fa);
 8         //printf("son = %d, father = %d, fa[son](xx)= %d, fa[father](yy) = %d,  \n", son, father, xx, yy);
 9         if (xx == yy) { return; }
10         xx < yy ? fa[yy] = xx : fa[xx] = yy;
11         //fa[xx] = yy;
12         //printf("son = %d, father = %d, fa[son] = %d, fa[father] = %d \n", son, father, xx, yy);
13     }
14     int arrayNesting(vector<int>& nums) {
15         const int n = nums.size();
16         if (n == 0) {
17             return 0;
18         }
19         vector<int> fa(n);
20         for (int i = 0; i < n; ++i) {
21             fa[i] = i;
22         }
23         for (int i = 0; i < n; ++i) {
24             int son = nums[i], father = i;
25             unionSet(son, father, fa);
26         }
27         
28         map<int, int> cnt;
29         int ans = 0;
30         for (int i = 0; i < n; ++i) {
31             fa[i] = findfa(fa[i], fa); //  加不加的影响在哪里,如何体现,这个要搞明白
32             cnt[fa[i]]++;
33             ans = max(ans, cnt[fa[i]]);
34         }
35         return ans;
36     }
37 };
View Code

 

【566】Reshape the Matrix 

 

【581】Shortest Unsorted Continuous Subarray 

给了一个不是完全递增的数组,求一个子数组,只要给这个子数组排序,那么整个数组就是有序的,求它的的最短长度。

Input: [2, 6, 4, 8, 10, 9, 15]
Output: 5
Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order to make the whole array sorted in ascending order.

题解:这个题目最开始想的是有点类似于冒泡排序,碰到一个不符合递增的数对,就给他们交换,有两个变量记录交换的开始下标和结束下标。

时间复杂度最坏达到O(n^2)

技术图片
 1 class Solution {
 2 public:
 3     int findUnsortedSubarray(vector<int>& nums) {
 4         const int n = nums.size();
 5         int begin = n, end = 0;
 6         for (int i = 0; i < n - 1; ++i) {
 7             int cur = i;
 8             while (cur >= 0 && nums[cur] > nums[cur+1]) {
 9                 begin = min(cur, begin);
10                 end = max(end, cur + 1);
11                 swap(nums[cur], nums[cur+1]);
12                 cur--;
13             }
14         }
15         return end - begin >= 0 ? end - begin + 1 : 0;
16         
17     }
18 };
View Code

 

【605】Can Place Flowers 

 

【611】Valid Triangle Number 

给了一个数组,求问数组中的这些元素一共能组成多少个三角形。

题解:先排序,然后三根指针遍历,时间复杂度是O(n^3)

技术图片
 1 class Solution {
 2 public:
 3     bool canForm(int a, int b, int c) {
 4         if (a + b > c) {
 5             if (c - b < a && c - a < b && b - a < c) {
 6                 return true;
 7             }
 8         }
 9         return false;
10     }
11     
12     int triangleNumber(vector<int>& nums) {
13         const int n = nums.size();
14         if (n < 3) { return 0; }
15         sort(nums.begin(), nums.end());
16         int ans = 0;
17         for (int i = 0; i < n - 2; ++i) {
18             for (int j = i + 1; j < n - 1; ++j) {
19                 for (int k = n - 1; k > j; --k) {
20                     if (canForm(nums[i], nums[j], nums[k])) {
21                         ans++;
22                     }
23                 }
24             }
25         }
26         return ans;
27     }
28 };
View Code

 

【621】Task Scheduler 

CPU要调度一些作业,作业用一个数组表示,给了一个整数n表示两个相同的作业之间必须有n的间隔,CPU要么执行作业,要么空闲。看下例子:

Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B 

问执行完所有作业的时间。

 

【624】Maximum Distance in Arrays 

给了m个有序数组,可以从任意两个数组中选择两个数字,使得这两个数字的距离最大。

题解:因为有可能最大值和最小值在同一个数组中,所以我们可以使用4个变量,最大值,最小值,次大值,次小值。

如果发现最大值和最小值在同一个数组中,就返回 次大 - 最小 和最大 - 次小 这两个数中比较大的一个。

思路简单,但是这题代码WA了好几遍,主要原因在于更新次小值/次大值的时候出了问题。

技术图片
 1 class Solution {
 2 public:
 3     int maxDistance(vector<vector<int>>& arrays) {
 4         const int m = arrays.size();
 5     
 6         int last0 = arrays[0].size()-1, last1 = arrays[1].size()-1;
 7         
 8         int global_max = arrays[0][last0], global_min = arrays[0][0]; //全局最大最小
 9         int global_max2 = arrays[1][last1], global_min2 = arrays[1][0]; //全局次大次小
10         
11         int global_max_idx = 0, global_min_idx = 0;
12         int global_max2_idx = 1, global_min2_idx = 1;
13         
14 
15         for (int i = 1; i < m; ++i) {
16             const int size = arrays[i].size();
17             if (global_max <= arrays[i][size-1]) {
18                 global_max2 = global_max, global_max2_idx = global_max_idx;
19                 global_max = arrays[i][size-1], global_max_idx = i;
20             } else if (global_max2 < arrays[i][size-1]) {
21                 global_max2 = arrays[i][size-1], global_max2_idx = i;
22             }
23             if (global_min >= arrays[i][0]) {
24                 global_min2 = global_min, global_min2_idx = global_min_idx;
25                 global_min = arrays[i][0], global_min_idx = i;
26             } else if (global_min2 > arrays[i][0]) {
27                 global_min2 = arrays[i][0], global_min2_idx = i;
28             }
29         }
30         int ans = 0;
31         /*
32         printf("global_max_idx = %d, global_max = %d, global_min_idx = %d, global_min = %d \n", global_max_idx, global_max, global_min_idx, global_min);
33         printf("global_max2_idx = %d, global_max2 = %d, global_min2_idx = %d, global_min2 = %d \n", global_max2_idx, global_max2, global_min2_idx, global_min2);
34         */
35         
36         if (global_max_idx != global_min_idx) {
37             ans = global_max - global_min;
38         } else {
39             ans = max(global_max - global_min2, global_max2 - global_min);
40         }
41         return ans;
42         
43     }
44 };
View Code

 

【628】Maximum Product of Three Numbers 

 

【643】Maximum Average Subarray I 

【644】Maximum Average Subarray II 

 

【661】Image Smoother 

给了一个矩阵代表像素点,想要平滑整个矩阵,平滑方法就是一个点的值更新成他周围八个点的值加上他本身的这九个数的平均值。返回整个更新后的矩阵。

题解:直接暴力求每个点的值了。

技术图片
 1 class Solution {
 2 public:
 3     vector<vector<int>> imageSmoother(vector<vector<int>>& M) {
 4         const int n = M.size();
 5         const int m = M[0].size();
 6         vector<vector<int>> ans(n, vector<int>(m, 0));
 7         for (int i = 0; i < n; ++i) {
 8             for (int j = 0; j < m; ++j) {
 9                 int s = M[i][j];
10                 int cnt = 1;
11                 for (int k = 0; k < 8; ++k) {
12                     int newx = i + dirx[k], newy = j + diry[k];
13                     if (newx >= 0 && newx < n && newy >= 0 && newy < m) {
14                         s += M[newx][newy];
15                         cnt++;
16                     }
17                 }
18                 ans[i][j] = s / cnt;
19             }
20         }
21         return ans;
22     }
23     int dirx[8] = {0, 0, 1, -1, 1, 1, -1, -1};
24     int diry[8] = {1,-1, 0, 0, 1, -1, 1, -1};
25 };
View Code

 

【665】Non-decreasing Array 

 

【667】Beautiful Arrangement II 

给了两个整数n和k,要求生成一个数组,数组元素是1~n之间的数,然后 abs(a1 - a2), abs(a2 - a3), abs(a3 - a4) .. abs(a[n-1] - a[n]), 这些相邻的元素中的差的绝对值有k个数 

Input: n = 3, k = 1
Output: [1, 2, 3]
Explanation: The [1, 2, 3] has three different positive integers ranging from 1 to 3, and the [1, 1] has exactly 1 distinct integer: 1.
Input: n = 3, k = 2
Output: [1, 3, 2]
Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2.

题解:我们发现如果需要k个数不同的差的绝对值,那么至少需要k+1个数。而这k个数可以是 1, 2, 3, 4,5 ,.. ,k

所以我们先搞一种特例就是 n = k + 1 的时候,我们产生这样的数组。产生的规律如下:

假如 n = 6, k = 5, 那么我们可以产生这么一种排列 A = {1, 6, 2, 5, 3, 4},  这样产生的差分别是 {-5, 4, -3, 2, -1} 满足条件。 产生的规则是 第一个数是 1, 然后+k, 得到第二个数, 第二个数 -(k-1) 得到第三个数, 依次类推。

那我们一般化下所有的case, 当 n > k + 1 的时候, 我们可以先生成能产生k个不同差的 前 k + 1 个数的数组,然后把生成的数组接到差全是1的数组的后面就行了。

技术图片
 1 class Solution {
 2 public:
 3     vector<int> constructArray(int n, int k) {
 4         vector<int> ans(n, 1);
 5         for (int i = 0; i < n; ++i) {
 6             ans[i] = i + 1;
 7         }
 8         if (k == 1) {
 9             return ans;
10         }
11         //gen diff k, need k +1 numbers
12         int newN = k + 1;
13         int cur_k = k;
14         vector<int> temp(k+1, 1);
15         for (int i = 1; i < k + 1; ++i) {
16             temp[i] = temp[i-1] + (i % 2 ? cur_k : -cur_k);
17             cur_k = (cur_k - 1);
18         }
19         /*
20         for (auto ele : temp) {
21             cout << ele << " ";
22         }
23         cout << endl;
24         */
25         int start = n - (k + 1);
26         for (int i = 0; i < k +1; ++i) {
27             ans[i + start] = temp[i] + start ;
28         }
29         return ans;
30     }
31 };
View Code

 

【670】Maximum Swap 

给了一个整数,最多交换两个数字,返回能得到的最大值。

eg1. 输入2736, 返回7236, 我们交换了数字7和数字2。 

eg2. 输入9973, 返回9973,这个数不需要交换,现在已经是最大的了。

题解:通过观察我们发现,如果这个整数需要使用交换这个操作得到更大的值,那么他不是一个单调递减的序列。所以我们从前往后找到第一个递增的数对,把较小的数和这个数对应的他后面的最大的数交换,这样能得到最大的数。

我用了一个数组记录 当前数nums[i] 往后到结尾的最大数的下标。

技术图片
 1 class Solution {
 2 public:
 3     int maximumSwap(int num) {
 4         string strNum = to_string(num);
 5         const int n = strNum.size();
 6         
 7         //用一个数组记录元素i(包含元素i和他之后所有元素的最大值)
 8         vector<int> maxFromEndIdx(n, -1);
 9         int maxNum = strNum[n-1] - 0, maxNumIdx = n-1;
10         for (int i = n - 1; i >= 0; --i) {
11             if (i == n - 1) {
12                 maxFromEndIdx[i] = n - 1;
13             } else {
14                 if (strNum[i] - 0 > maxNum) { //不能取等号,比如输入1993,应该返回9913,如果取了等号就会返回9193
15                     maxNum = strNum[i] - 0;
16                     maxNumIdx = i;
17                 }
18                 maxFromEndIdx[i] = maxNumIdx;
19             }
20         }
21         
22         //从前往后找,然后交换
23         for (int i = 0; i < n; ++i) {
24             if (maxFromEndIdx[i] != i && strNum[maxFromEndIdx[i]] != strNum[i]) {
25                 swap(strNum[i], strNum[maxFromEndIdx[i]]);
26                 break;
27             }
28         }
29         
30         int ans = atoi(strNum.c_str());
31         return ans;
32     }
33 };
View Code

  

【674】Longest Continuous Increasing Subsequence 

给了一个无序数组,返回最长递增子数组的长度。

题解:直接数就行了。

技术图片
 1 class Solution {
 2 public:
 3     int findLengthOfLCIS(vector<int>& nums) {
 4         const int n = nums.size();
 5         if (n == 0) {
 6             return 0;
 7         }
 8         int ans = 1;
 9         int temp = 1;
10         for (int i = 0; i < n - 1; ++i) {
11             if (nums[i] < nums[i+1]) {
12                 temp++;
13                 ans = max(ans, temp);
14             } else {
15                 temp = 1;
16             }
17         }
18         return ans;
19     }
20 };
View Code

 

【683】K Empty Slots 

一个花园里面有N个花槽,每个花槽里面能种一朵花,N个花槽里面的花每天盛开一朵,花一旦盛开就从盛开那天开始一直开着。给了一个数组flowers, flowers[i] = x 表示位置在 x 的花在第 i 天开放。i 和 x 都在 [1, N] 之间。

给了一个整数k, 问在哪一天能存在两朵位置相差k的花同时开放,但是这两朵花中间夹的这些花不开。

Input: 
flowers: [1,3,2]
k: 1
Output: 2
Explanation: In the second day, the first and the third flower have become blooming. 

题解:我们求一个反数组,pos数组, pos[x] = i 表示位置在x的花在第i天开放。依照题意,我们需要求这么一个子数组 pos[i] .. pos[i+k], 需要满足的条件是 pos[i+1], pos[i+2], pos[i+3], .., pos[i+k-1] 这些值都大于 max(pos[i], pos[i+k])

技术图片
 1 class Solution {
 2 public:
 3     int kEmptySlots(vector<int>& flowers, int k) {
 4         const int n = flowers.size();
 5         vector<int> pos(n, 0);
 6         for (int i = 0; i < n; ++i) {
 7             int day = i, p = flowers[i];
 8             pos[p-1] = day;
 9         }
10         /*
11         for (auto ele : pos) {
12             cout << ele  << " ";
13         }
14         cout << endl;
15         */
16         int ans = n + 1;
17         for (int i = 0; i + k +1 < n; ++i) {
18             int pbegin = i, pend = i +k +1;
19             //printf("beginDay = %d, endDay = %d \n", pbegin, pend);
20             int bloomDay = max(pos[pbegin], pos[pend]); //0-based
21             //printf("beginPos = %d, beginDay = %d, endPos = %d ,endDay = %d \n", pbegin, pos[pbegin], pend, pos[pend]);
22             bool check = true;
23             for (int j = pbegin + 1; j < pend; ++j) {
24                 if (pos[j] <= bloomDay) {
25                     check = false;
26                     break;
27                 }
28             }
29             if (check == false) {
30                 continue;
31             }
32             if (check) {
33                 ans = min(bloomDay + 1, ans);
34             }
35         }
36         return ans == n + 1 ? -1 : ans;
37     }
38 };
View Code

 

【689】Maximum Sum of 3 Non-Overlapping Subarrays 

 

【695】Max Area of Island 

【697】Degree of an Array 

一个数组的度定义为它所有元素中频次出现最高的那个元素,找出这个数组中的一个长度最短的子数组,它的度和原数组相同。

 题解:先找出频次最高的所有元素,存在一个数组number中,然后依次遍历number数组中所有元素,得到满足条件的最短数组的长度。

技术图片
 1 class Solution {
 2 public:
 3     int findShortestSubArray(vector<int>& nums) {
 4         const int n = nums.size();
 5         map<int, int> count;
 6         int maxFreq = 0;
 7         for (int i = 0; i < n; ++i) {
 8             count[nums[i]]++;
 9             maxFreq = max(maxFreq, count[nums[i]]);
10         }
11         if (maxFreq == 1) {
12             return 1;
13         }
14         vector<int> number;
15         for (auto ele : count) {
16             if (ele.second == maxFreq) {
17                 number.push_back(ele.first);
18             }
19         }
20         int minLen = INT_MAX;
21         for (int i = 0; i < number.size(); ++i) {
22             int target = number[i];
23             int left = 0, right = n - 1;
24             while (nums[left] != target) {left++;}
25             while (nums[right] != target) {right--;}
26             minLen = min(minLen, right - left + 1);
27         }
28         return minLen;
29     }
30 };
View Code

 

【713】Subarray Product Less Than K 

 

【714】Best Time to Buy and Sell Stock with Transaction Fee 

【715】Range Module 

【717】1-bit and 2-bit Characters 

题目定义了两种特殊字符,第一种定义成1bit表示的0,第二种定义成2个bits表示的10或者11,给了一个用几个bits表示的字符串,返回这个字符串的最后一个字符能不能用1bit字符表示。

题解:根据观察我们可以发现,如果是1开头的字符,后面必然跟着另外一个字符,凑成2bits表示的字符,如果是0开头的,那么它必然是1bit的字符。于是我们用一个cur指针指向一开始的字符串头部,然后依次遍历字符串就ok。

技术图片
 1 class Solution {
 2 public:
 3     bool isOneBitCharacter(vector<int>& bits) {
 4         const int n = bits.size();
 5         int i = 0;
 6         int pre = -1;
 7         for (; i < n; ) {
 8             if (bits[i] == 1) {
 9                 i += 2;
10                 pre = 2;
11             } else if (bits[i] == 0) {
12                 i += 1;
13                 pre = 1;
14             }
15         } 
16         if (pre == 1) {
17             return true;
18         }
19         return false;
20     }
21 };
View Code

 

【718】Maximum Length of Repeated Subarray 

【719】Find K-th Smallest Pair Distance 

【723】Candy Crush 

题意就是模拟candy crush 那个游戏,纯粹的模拟题。

题解:有个点需要注意,有的字符不仅仅是同一行或者同一列,有的会有一个L型。所以不能发现同行或者同列就开始消,应该先遍历矩阵,把所有能消除的方块的位置先记录下来。

技术图片
  1 class Solution {
  2 public:
  3     typedef pair<int, int> P;
  4     
  5     void print(vector<pair<P, P>>& coor) {
  6         for (auto ele : coor) {
  7             P pstart = ele.first, pend = ele.second;
  8             printf("start = [%d, %d], end = [%d, %d] \n", pstart.first, pstart.second, pend.first, pend.second);
  9         }
 10     }
 11     void print(vector<vector<int>>& board) {
 12         const int n = board.size();
 13         const int m = board[0].size();
 14         for (int i = 0; i < n; ++i) {
 15             for (int j = 0; j < m; ++j) {
 16                 cout << setw(5) << board[i][j] << " ";
 17             }
 18             cout << endl;
 19         }
 20     }
 21     
 22     void print(vector<int>& temp) {
 23         for (int i = 0; i < temp.size(); ++i) {
 24             cout << temp[i] << " ";
 25         }
 26         cout << endl;
 27     }
 28     
 29     //opt 1 = check left -> right
 30     //opt 2 = check top -> bottom
 31     bool checkRepeat(vector<pair<P, P>>& coor, P& pstart, P& pend, int opt) {
 32         for (int i = 0; i < coor.size(); ++i) {
 33             if (opt == 1) {
 34                 if (pend == coor[i].second && pstart.first == coor[i].first.first) {
 35                     return true;
 36                 }  
 37             }
 38             if (opt == 2) {
 39                 if (pend == coor[i].second && pstart.second == coor[i].first.second) {
 40                     return true;
 41                 }
 42             }
 43         }
 44         return false;
 45     }   
 46     
 47     bool check(const vector<vector<int>>& board, vector<pair<P, P>>& coor) {
 48         const int n = board.size(), m = board[0].size();
 49         for (int i = 0; i < n; ++i) {
 50             for (int j = 0; j < m; ++j) {
 51                 //left -> right
 52                 int row = i, colStart = j, colEnd = j;
 53                 while (colEnd + 1 < m && board[row][colEnd+1] == board[row][colEnd] && board[row][colStart] != 0) {
 54                     colEnd++;
 55                 }
 56                 P pstart = make_pair(row, colStart), pend = make_pair(row, colEnd);
 57                 if (colEnd - colStart >= 2 && checkRepeat(coor, pstart, pend, 1) == false) {
 58                     coor.push_back(make_pair(pstart, pend));
 59                 }
 60                 //top -> bottom
 61                 int col = j, rowStart = i, rowEnd = i;
 62                 while (rowEnd + 1 < n && board[rowEnd+1][col] == board[rowEnd][col] && board[rowStart][col] != 0) {
 63                     rowEnd++;
 64                 }
 65                 P pstart2 = make_pair(rowStart, col), pend2 = make_pair(rowEnd, col);
 66                 if (rowEnd - rowStart >= 2 && checkRepeat(coor, pstart2, pend2, 2) == false) {
 67                     coor.push_back(make_pair(pstart2, pend2));
 68                 }
 69             }
 70         }
 71         return !coor.empty();
 72     }
 73     void clear(vector<vector<int>>& board, const vector<pair<P, P>>& coor) {
 74         for (int idx = 0; idx < coor.size(); ++idx) {
 75             P pstart = coor[idx].first, pend = coor[idx].second;
 76             if (pstart.first == pend.first) { // left -> right
 77                 const int row = pstart.first;
 78                 const int colStart = pstart.second, colEnd = pend.second;
 79                 for (int k = colStart; k <= colEnd; ++k) {
 80                     board[row][k] = 0;
 81                 }
 82             } else { //top -> bottom
 83                 const int col = pstart.second;
 84                 const int rowStart = pstart.first, rowEnd = pend.first;
 85                 for (int k = rowStart; k <= rowEnd; ++k) {
 86                     board[k][col] = 0;
 87                 }
 88             }
 89         }
 90 
 91         // make upper ele down
 92         vector<vector<int>> boardNew = board;
 93         const int n = board.size(), m = board[0].size();
 94         for (int col = 0; col < m; ++col) {
 95             vector<int> temp(n, 0);
 96             int ptr = n - 1, cur = n - 1;
 97             while (ptr >= 0) {
 98                 if (board[ptr][col] != 0) {
 99                     temp[cur] = board[ptr][col];
100                     cur--;
101                 }
102                 ptr--;
103             }
104             for (int i = n -1; i >= 0; --i) {
105                 board[i][col] = temp[i];
106             }
107         }
108         return;
109     }
110 
111     vector<vector<int>> candyCrush(vector<vector<int>>& board) {
112         const int n = board.size();
113         const int m = board[0].size();
114         vector<pair<P, P>> coor;
115         while (check(board, coor)) {
116             clear(board, coor);
117             coor.clear();
118         }
119         return board;
120     }
121 };
View Code

 

【724】Find Pivot Index 

给了一个数组,求一个pivot下标,它的定义是在它左边所有的元素和等于它右边所有的元素和。

题解:two pointers

技术图片
 1 class Solution {
 2 public:
 3     int pivotIndex(vector<int>& nums) {
 4         const int n = nums.size();
 5         if (n == 1) {
 6             return 0;
 7         }
 8         int leftsum = 0;
 9         int rightsum = 0;
10         for (int i = n - 1; i >= 0; --i) {
11             rightsum += nums[i];
12         }
13         for (int pivot = 0; pivot < n; ++pivot) {
14             leftsum += nums[pivot];
15             if (leftsum == rightsum) {
16                 return pivot;
17             }
18             rightsum -= nums[pivot];
19         }
20         return -1;
21     }
22 };
View Code

 

【729】My Calendar I 

【731】My Calendar II 

【746】Min Cost Climbing Stairs 

【747】Largest Number At Least Twice of Others 

【755】Pour Water 

【766】Toeplitz Matrix 

【768】Max Chunks To Make Sorted II 

【769】Max Chunks To Make Sorted 

【775】Global and Local Inversions 

【782】Transform to Chessboard 

【792】Number of Matching Subsequences 

【795】Number of Subarrays with Bounded Maximum 

 

【825】Friends Of Appropriate Ages (2019年1月1日,算法群,我记得本题在模拟赛的时候做过,当时没有用计数的方法)

给个一个数组代表人的年龄,任选两个人,如果满足如下任何一个条件,就不能发 friend request。问这些人可以发多少个 friend request。

  • age[B] <= 0.5 * age[A] + 7

  • age[B] > age[A]

  • age[B] > 100 && age[A] < 100

数据规模:

  • 1 <= ages.length <= 20000.
  • 1 <= ages[i] <= 120.

题解:我们先遍历一下数组,然后数出每个年龄有几个人。然后用cnt数组二重循环找ageA和ageB。

技术图片
 1 class Solution {
 2 public:
 3     int numFriendRequests(vector<int>& ages) {
 4         const int n = ages.size();
 5         vector<int> cnt(121, 0);
 6         for (auto age : ages) {
 7             cnt[age]++;
 8         }
 9         int ret = 0;
10         for (int ageA = 1; ageA <= 120; ++ageA) {
11             int countA = cnt[ageA];
12             for (int ageB = 1; ageB <= 120; ++ageB) {
13                 int countB = cnt[ageB];
14                 if (ageB <= ageA / 2 + 7) {continue;}
15                 if (ageB > ageA) {continue;}
16                 if (ageB > 100 && ageA < 100) {continue;}
17                 ret += ageA == ageB ? (countA-1) * countA : countA * countB;
18             }
19         }
20         return ret;
21     }
22 };
View Code

 

 

【830】Positions of Large Groups 

【832】Flipping an Image 

 

【835】Image Overlap (2018年11月20日,算法群)

题目给了A,B两个相同大小的 0/1 矩阵(矩阵长和宽相同都是N),问两个矩阵开始重叠的时候最多的 1 的个数是多少。

题解:暴力求解, O(N^4)。枚举offsetX,offsetY,在根据矩阵A的坐标和offset去计算另外一个矩阵的坐标。

技术图片
 1 //暴力求解 O(N^4)
 2 class Solution {
 3 public:
 4     int largestOverlap(vector<vector<int>>& A, vector<vector<int>>& B) {
 5         n = A.size();
 6         return max(helper(A, B), helper(B, A));
 7     }
 8     int n;
 9     int helper(vector<vector<int>>& A, vector<vector<int>>& B) {
10         int res = 0;
11         for (int offsetX = 0; offsetX < n; ++offsetX) {
12             for (int offsetY = 0; offsetY < n; ++offsetY) {
13                 int cnt = 0;
14                 for (int i = offsetX; i < n; ++i) {
15                     for (int j = offsetY; j < n; ++j) {
16                         if (A[i][j] == 1 && B[i-offsetX][j-offsetY] == 1) {
17                             cnt++;
18                         }
19                     }
20                 }
21                 res = max(cnt, res);
22             }
23         }
24         return res;
25     }
26 };
View Code

discuss 里面有 O(N^2) 的解答:https://leetcode.com/problems/image-overlap/discuss/130623/C++JavaPython-Straight-Forward

 

【840】Magic Squares In Grid 

【849】Maximize Distance to Closest Person 

【867】Transpose Matrix 

【870】Advantage Shuffle 

【873】Length of Longest Fibonacci Subsequence 

【888】Fair Candy Swap 

【891】Sum of Subsequence Widths 

【896】Monotonic Array 

【LeetCode】数组

标签:最小   年龄   多少   滑动   oba   break   play   longest   操作   

原文地址:https://www.cnblogs.com/zhangwanying/p/9610923.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!