【LeetCode】Array

[11] Container With Most Water [Medium]

O(n^2)的暴力解法直接TLE。

正确的解法是Two Pointers。 O(n)的复杂度。保持两个指针i,j;分别指向长度数组的首尾。如果ai 小于aj,则移动i向后(i++)。反之,移动j向前(j--)。如果当前的area大于了所记录的area,替换之。这个想法的基础是,如果i的长度小于j,无论如何移动j,短板在i,不可能找到比当前记录的area更大的值了,只能通过移动i来找到新的可能的更大面积。

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

 

[15] 3Sum [Medium]

它要求返回结果不重复,所以去重。不能用unique,会TLE,直接在循环里面跳过。

先排序,两根指针,夹逼定理

 1 class Solution {
 2 public:
 3     vector<vector<int>> threeSum(vector<int>& nums) {
 4         vector<vector<int>> result;
 5         if (nums.size() < 3) {
 6             return result;
 7         }
 8         sort(nums.begin(), nums.end());
 9         for (int i = 0; i < nums.size(); ) {
10             int j = i + 1;
11             int k = nums.size() - 1;
12             while (j < k) {
13                 if (nums[i] + nums[j] + nums[k] == 0) {
14                     result.push_back(vector<int>{nums[i], nums[j], nums[k]});
15                     ++j, --k;
16                     while (j < k && nums[j-1] == nums[j]) { ++j; }
17                     while (j < k && nums[k+1] == nums[k]) { --k; }
18                 }
19                 else if (nums[i] + nums[j] + nums[k] < 0) {
20                     ++j;
21                     while (j < k && nums[j-1] == nums[j]) { ++j; }
22                 }
23                 else {
24                     --k;
25                     while (j < k && nums[k+1] == nums[k]) { --k; }
26                 }
27             }
28             ++i;
29             while (nums[i-1] == nums[i]) { ++i; }
30         }
31         return result;
32     }
33 };
View Code

 

[16] 3Sum Closest [Medium]

三个数求和,返回离target最近的和。

Two Pointers, 跟15题一样, 先排序,两根指针左右夹逼。

 1 class Solution {
 2 public:
 3     int threeSumClosest(vector<int>& nums, int target) {
 4         int result = 0;
 5         int min_gap = INT_MAX;
 6         sort(nums.begin(), nums.end());
 7         for (int i = 0; i < nums.size() - 2; ++i) {
 8             int start = i + 1, end = nums.size() - 1;
 9             while (start < end) {
10                 int temp = nums[i] + nums[start] + nums[end];
11                 int gap = abs(temp - target);
12                 if (gap < min_gap) {
13                     min_gap = gap;
14                     result = temp;
15                 }
16                 if (temp == target) break;
17                 if (temp > target) {
18                     --end;
19                 }
20                 else if (temp < target) {
21                     ++start;
22                 }
23             }
24         }
25         return result;
26     }
27 };
View Code

 

[17] 4Sum [Medium]

四个数求和,求出和target相等的元组, 思路和3sum一个样,包括和去重的方式都一样。

还是先排序,然后两根指针。

 1 class Solution {
 2 public:
 3     vector<vector<int>> fourSum(vector<int>& nums, int target) {
 4         vector<vector<int>> result;
 5         if (nums.size() < 4) {
 6             return result;
 7         }
 8         sort(nums.begin(), nums.end());
 9         for (int i = 0; i < nums.size()-3; ) {
10             for(int j = i+1; j < nums.size()-2; ) {
11                 int start = j + 1, end = nums.size() - 1;
12                 while (start < end) {
13                     int sum = nums[i] + nums[j] + nums[start] + nums[end];
14                     if (sum == target) {
15                         result.push_back(vector<int>{nums[i], nums[j], nums[start], nums[end]});
16                         ++start, --end;
17                         while (start < end && nums[start-1] == nums[start]) {
18                             ++start;
19                         }
20                         while (start < end && nums[end+1] == nums[end]) {
21                             --end;
22                         }
23                     }
24                     else if (sum < target) {
25                         ++start;
26                         while (start < end && nums[start-1] == nums[start]) {
27                             ++start;
28                         }
29                     }
30                     else {
31                         --end;
32                         while (start < end && nums[end+1] == nums[end]) {
33                             --end;
34                         }
35                     }
36                 }
37                 ++j;
38                 while (nums[j-1] == nums[j]) { ++j; }
39             }
40             ++i;
41             while(nums[i-1] == nums[i]) { ++i; }
42         }
43         return result;
44     }
45 };
View Code

 

[45] Jump Game II [Hard]

这个题需要记忆。再考肯定不会。。。要记忆。。。

给你一个数组,数组元素的值是从当前index最多能往前面移动的步数,求到数组末尾最少移动的步数。

我是参考了这个:https://www.tianmaying.com/tutorial/LC45

 1 /*
 2 将每个位置都看作一个点,并从第i个点向它之后的nums[i]个点都连一条长度为1的有向边,而现在的问题就是从0号点到达size-1号点需要的最短距离,这就是一个很简单的最短路问题,实际上由于边的长度均为1,而且不存在环,我们可以用宽度优先搜索(时间复杂度为O(n^2),即边数)来进行相关的计算。
 3 
 4 不难发现,这道题目转换出的最短路问题存在三个条件:
 5 
 6 边的长度均为1
 7 不存在环
 8 连出的边是连续的
 9 我们是不是可以用这三个“很强”的条件来做一些优化呢,答案自然是肯定的!
10 
11 ——如果令f[i]表示从0号点到达i号点的最短路径,那么对于任意i<j,有f[i]<=f[j],即f是非递减的,这个结论的证明是显然的,在此不作过多赘述。
12 
13 在有了这样的结论之后,我们就会发现,其实对于f数组来说,它会是一段段的存在,先是一个0,然后是一段1,然后是一段2,依此类推,那么现在问题来了,每一段的长度是多少呢?
14 
15 这个问题很好回答,如果我们令l[k]表示f数组中值为k的一段的左边界,r[k]表示f数组中值为k的一段的有边界,那么有
16 
17 l[k] = r[k - 1] + 1,这是显然的
18 r[k] = max{i + nums[i] | l[k - 1] <= i <= r[k - 1]},由于f值为k的位置一定是从f值为k-1的位置走来的,所以只需要看从所有f值为k-1的位置里最远可以到达的地方即可。
19 也就是说,我们可以在对nums的一遍扫描中,依次求出所有的l[k]和r[k],而f数组也就自然求解出来了——答案也就得到了。
20 */
View Code

 

 1 class Solution {
 2 public:
 3     int jump(vector<int>& nums) {
 4         int k = 0, l = 0, r = 0;
 5         while (r < nums.size()-1) {
 6             int next_r = r;
 7             for (int i = l; i <= r; ++i) next_r = max(next_r, nums[i]+i);
 8             ++k; l = r + 1; r = next_r; 
 9         }
10         return k;
11     }
12 };
View Code

 

[48] Rotate Image [Medium]

题目要求一个方阵顺时针旋转90°。

经过研究发现顺时针旋转90°,相当于先转置,再每行逆序。要学会矩阵转置的写法

 1 class Solution {
 2 public:
 3     void rotate(vector<vector<int>>& matrix) {
 4         const int N = matrix.size();
 5         //trans
 6         for (int i = 0; i < N; ++i) {
 7             for (int j = i+1; j < N; ++j) {
 8                 swap(matrix[i][j], matrix[j][i]);
 9             }
10         }
11         
12         //reverse
13         for (int i = 0; i < N; ++i) {
14             int start = 0, end = N - 1;
15             while (start < end) {
16                 swap(matrix[i][start++], matrix[i][end--]);
17             }
18         }
19     }
20 };
View Code

 

[54] Spiral Matrix [Medium]

打印旋转矩阵。 设置有用的四个变量 beginx, beginy, endx, endy。然后用一个i去遍历。

 1 class Solution {
 2 public:
 3     vector<int> spiralOrder(vector<vector<int>>& matrix) {
 4         vector<int> ans;
 5         if (matrix.size() == 0) {
 6             return ans;
 7         }
 8         const int m = matrix.size();
 9         const int n = matrix[0].size();
10         int beginx = 0, beginy = 0;
11         int endx = n-1, endy = m - 1;
12         while (true) {
13             for (int i = beginx; i <= endx; ++i) {
14                 ans.push_back(matrix[beginy][i]);
15             }
16             ++beginy;
17             if (beginy > endy) break;
18             
19             for (int i = beginy; i <= endy; ++i) {
20                 ans.push_back(matrix[i][endx]);
21             }
22             --endx;
23             if (beginx > endx) break;
24             
25             for (int i = endx; i >= beginx; --i) {
26                 ans.push_back(matrix[endy][i]);
27             }
28             --endy;
29             if (beginy > endy) break;
30             
31             for (int i = endy; i >= beginy; --i) {
32                 ans.push_back(matrix[i][beginx]);
33             }
34             ++beginx;
35             if (beginx > endx) break;
36         }        
37         return ans;
38     }
39 };
View Code

 

[56] Merge Intervals [Hard]

合并线段(数轴) 参考57题。 在 Insert Interval的基础上,一个新的interval集合,然后每次从旧的里面取一个interval出来,然后插入到新的集合中。

 1 /**
 2  * Definition for an interval.
 3  * struct Interval {
 4  *     int start;
 5  *     int end;
 6  *     Interval() : start(0), end(0) {}
 7  *     Interval(int s, int e) : start(s), end(e) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<Interval> merge(vector<Interval>& intervals) {
13         vector<Interval> ans;
14         if (intervals.size() == 0) {
15             return ans;
16         }
17         ans.push_back(intervals[0]);
18         for (int i = 1; i < intervals.size(); ++i) {
19             insert_interval(ans, intervals[i]);
20         }
21         return ans;
22     }
23     vector<Interval> insert_interval(vector<Interval>& intervals, Interval newInterval) {
24         vector<Interval>::iterator it = intervals.begin();
25         while (it != intervals.end()) {
26             if (it->start > newInterval.end) {
27                 break;    
28             }
29             else if (it->end < newInterval.start) {
30                 it++;
31                 continue;
32             }
33             else {
34                 newInterval.start = min(newInterval.start, it->start);
35                 newInterval.end = max(newInterval.end, it->end);
36                 intervals.erase(it);
37             }
38         }
39         intervals.insert(it, newInterval);
40         return intervals;
41     }
42 };
View Code

 

[57] Insert Interval [Hard]

先判断是否能放在最前面,然后在现有的intervals中一个一个遍历。有覆盖就更新newInterval,然后把原本的那段删除。

 1 /**
 2  * Definition for an interval.
 3  * struct Interval {
 4  *     int start;
 5  *     int end;
 6  *     Interval() : start(0), end(0) {}
 7  *     Interval(int s, int e) : start(s), end(e) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
13         vector<Interval>::iterator it = intervals.begin();
14         while (it != intervals.end()) {
15             if (it->start > newInterval.end) {
16                 break;
17             }
18             else if (it->end < newInterval.start) {
19                 ++it;
20                 continue;
21             }
22             else {
23                 newInterval.start = min(it->start, newInterval.start);
24                 newInterval.end = max(it->end, newInterval.end);
25                 intervals.erase(it);
26             }
27         }
28         intervals.insert(it, newInterval);
29         return intervals;
30     }
31 };
View Code

 

[59] Spiral Matrix II [Medium]

跟前一题Spiral Matrix的区别是前一题是遍历, 这个题是造一个矩阵出来。 思路写法都一样。

 1 class Solution {
 2 public:
 3     vector<vector<int>> generateMatrix(int n) {
 4         vector<vector<int>> matrix(n, vector<int>(n, 0));
 5         if (n == 0) {
 6             return matrix;
 7         }
 8         int number = 1;
 9         int beginx = 0, beginy = 0, endx = n - 1, endy = n - 1;
10         while (true) {
11             for (int i = beginx; i <= endx; ++i) {
12                 matrix[beginy][i] = number++;
13             }
14             ++beginy;
15             if (beginy > endy) { break; }
16             
17             for (int i = beginy; i <= endy; ++i) {
18                 matrix[i][endx] = number++;
19             }
20             --endx;
21             if (beginx > endx) { break; }
22 
23             for (int i = endx; i >= beginx; --i) {
24                 matrix[endy][i] = number++;
25             }            
26             --endy;
27             if (beginy > endy) { break; }
28             
29             for (int i = endy; i >= beginy; --i) {
30                 matrix[i][beginx] = number++;
31             }
32             ++beginx;
33             if (beginx > endx) { break; }
34         }
35         return matrix;
36     }
37 };
View Code

 

[73] Set Matrix Zeroes [Medium]

如果矩阵中一个元素为0, 那么把该元素所在的行和列都置零。O(1)的空间复杂度

思路:有个简单的O(m+n)的空间复杂度的,就是设两个布尔数组,来控制行和列是否为0.

但是如果要降低到O(1)的话,就可以牺牲第0行和第0列来存这两个数组。提前用两个变量保存好第0行,第0列是否置0.

 1 class Solution {
 2 public:
 3     void setZeroes(vector<vector<int>>& matrix) {
 4         const int m = matrix.size();
 5         if (m == 0) return;
 6         const int n = matrix[0].size();
 7         bool row_has_zero = false;
 8         bool col_has_zero = false;
 9         for (size_t i = 0; i < m; ++i) {
10             if (matrix[i][0] == 0) {
11                 col_has_zero = true;
12                 break;
13             }
14         }
15         for (size_t j = 0; j < n; ++j) {
16             if (matrix[0][j] == 0) {
17                 row_has_zero = true;
18                 break;
19             }
20         }
21         
22         for (size_t i = 1; i < m; ++i) {
23             for (size_t j = 1; j < n; ++j) {
24                 if (matrix[i][j] == 0) {
25                     matrix[i][0] = 0;
26                     matrix[0][j] = 0;
27                 }
28             }
29         }
30         
31         for (size_t i = 1; i < m; ++i) {
32             for (size_t j = 1; j < n; ++j) {
33                 if (matrix[i][0] == 0 || matrix[0][j] == 0) {
34                     matrix[i][j] = 0;
35                 }
36             }
37         }
38         
39         if (col_has_zero == true) {
40             for (size_t i = 0; i < m; ++i) {
41                 matrix[i][0] = 0;
42             }
43         }
44         
45         if (row_has_zero == true) {
46             for (size_t j = 0; j < n; ++j) {
47                 matrix[0][j] = 0;
48             }
49         }
50         return;
51     }
52 };
View Code

 

[118] Pascal's Triangle [Easy]

 1 class Solution {
 2 public:
 3     vector<vector<int>> generate(int numRows) {
 4         vector<vector<int>> ans;
 5         if (numRows == 0) return ans;
 6         for (size_t i = 0; i < numRows; ++i) {
 7             vector<int> ans_row(i+1, 1);
 8             if (i == 0 || i == 1) {
 9                 ans.push_back(ans_row);
10                 continue;
11             }
12             for (size_t j = 1; j < i ; ++j) {
13                 ans_row[j] = ans[i-1][j-1] + ans[i-1][j];
14             }
15             ans.push_back(ans_row);
16         }
17         return ans;
18     }
19 };
View Code

 

[119] Pascal's Triangle II [Easy]

只要求O(k)的额外空间。我自己写的解法用了两个数组,其实一个就够了。

 1 class Solution {
 2 public:
 3     vector<int> getRow(int rowIndex) {
 4        vector<int> ans(rowIndex+1, 1);
 5        vector<int> help(rowIndex+1, 0);
 6        if (rowIndex == 0 || rowIndex == 1) {
 7            return ans;
 8        }
 9        for (size_t i = 2; i < rowIndex+1; ++i) {
10            help = ans;
11            for (size_t j = 1; j < i; ++j) {
12                 ans[j] = help[j-1] + help[j];       
13            }
14            ans[i] = 1;
15        }
16        return ans;
17     }
18 };
View Code

一个数组的还没看懂(好困,睡了==)

 1 class Solution {
 2 public:
 3     vector<int> getRow(int rowIndex) {
 4         vector<int> A(rowIndex+1, 0);
 5         A[0] = 1;
 6         for(int i=1; i<rowIndex+1; i++)
 7             for(int j=i; j>=1; j--)
 8                 A[j] += A[j-1];
 9         return A;
10     }
11 };
View Code

 

posted @ 2016-12-05 23:59  zhangwanying  阅读(164)  评论(0编辑  收藏  举报