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

【LeetCode】数组

时间:2018-12-25 10:15:44      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:ring   有序数组   setw   选择   hunk   条件   指针   sch   push   

【1】Two Sum 

【4】Median of Two Sorted Arrays 

【11】Container With Most Water 

【15】3Sum 

【16】3Sum Closest 

【18】4Sum 

【26】Remove Duplicates from Sorted Array 

 

【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 

 

【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 

【42】Trapping Rain Water 

【45】Jump Game II 

【48】Rotate Image 

【53】Maximum Subarray 

【54】Spiral Matrix 

【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 

【370】Range Addition 

【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 

【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 

【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】数组

标签:ring   有序数组   setw   选择   hunk   条件   指针   sch   push   

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

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