LeetCode数组解题模板
一、模板以及题目分类
1、头尾指针向中间逼近
int pos1 = 0; int pos2 = nums.size() - 1; while (pos1<pos2) { //判断条件 //pos更改条件 if (nums[pos1]<nums[pos2]) pos1++; else pos2--; }
经典的找和的问题都可以从这种思路下手,2数之和,3数之和,还注意要区分是寻找值还是索引(寻找索引则不能排序),是否允许有重复,不允许重复时要怎样避开重复值。
避开重复值的方法,当然,在3sum和4sum中的ij要稍微做修改
while(i<nums.size()-1 && nums[i] == nums[i+1]){ i++; } i++;
11. Container With Most Water https://leetcode.com/problems/container-with-most-water/description/
int maxArea(vector<int>& height) { int max = 0; int pos1 = 0; int pos2 = height.size() - 1; while (pos1<pos2) { int temp = min(height[pos1], height[pos2])*(pos2 - pos1); if (temp>max) { max = temp; } if (height[pos1]<height[pos2]) pos1++; else pos2--; } return max; }
1、注意什么时候左指针加,什么时候右指针减
15. 3Sum https://leetcode.com/problems/3sum/description/
sort(nums.begin(), nums.end()); vector<vector<int>> res; for (unsigned int i = 0; i<nums.size(); i++) { if ((i>0) && (nums[i] == nums[i - 1])) continue; int l = i + 1, r = nums.size() - 1; while (l<r) { int s = nums[i] + nums[l] + nums[r]; if (s>0) r--; else if (s<0) l++; else { res.push_back(vector<int> {nums[i], nums[l], nums[r]}); while (l<r && nums[l] == nums[l + 1]) l++; l++; } } } return res;
1、在找到合适的组合之后需要一定一个索引值,不然循环就不能继续了
2、注意怎样去除重复值
16. 3Sum Closest https://leetcode.com/problems/3sum-closest/description/
1、再做一下熟悉一下
sort(nums.begin(),nums.end()); int result = INT_MAX; int min = INT_MAX; for(size_t i=0;i<nums.size()-2;i++){ int j = i+1; int k = nums.size()-1; while(j<k){ int temp = nums[i]+nums[j]+nums[k]; if(abs(temp-target)<min){ result = temp; min = abs(temp-target); } if(temp < target){ j++; }else if(temp > target){ k--; }else if(temp == target){ return temp; } } } return result;
18、4sum https://leetcode.com/problems/4sum/description/
vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> result; if(nums.size() < 4) return result; sort(nums.begin(),nums.end()); for(size_t i = 0;i<nums.size()-3;){ for(size_t j =i+1;j<nums.size()-2;){ int k = j+1; int l = nums.size()-1; while(k<l){ if(nums[i]+nums[j]+nums[k]+nums[l] == target){ result.push_back(vector<int>{nums[i],nums[j],nums[k],nums[l]}); while(k<nums.size()-1 && nums[k] == nums[k+1])k++;k++; }else if(nums[i]+nums[j]+nums[k]+nums[l] < target){ while(k<nums.size()-1 && nums[k] == nums[k+1])k++;k++; }else{ while(l>1 && nums[l] == nums[l-1])l--;l--; } } while(j<nums.size()-2 && nums[j] == nums[j+1])j++;j++; } while(i<nums.size()-3 && nums[i] == nums[i+1])i++;i++; } return result; }
2、数组内部移位
size_t pos1 = 0;//目的位置 //i为开始位置 for(size_t i =0;i<nums.size();i++){ //条件 if(nums[i] != val){ //数组整体向前移 nums[pos1++] = nums[i]; } } return pos1;
需要维持一个开始位置,和一个目的位置,直接看例子
26. Remove Duplicates from Sorted Array https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/
int removeDuplicates(vector<int> nums) { if (nums.size() == 0) return 0; size_t pos = 1; for (size_t i = 1; i < nums.size(); i++) { if (nums[i - 1] != nums[i]) nums[pos++] = nums[i]; } return pos - 1; }
1、如果前一个等于当前,代表当前值是重复,反之,如果不是则需要将当前值移位到pos处
2、边界条件,pos是从1开始,因为前一个存在的情况至少要从1开始
27. Remove Element https://leetcode.com/problems/remove-element/description/
同上一个方法
80. Remove Duplicates from Sorted Array II https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/description/
class Solution { public: int removeDuplicates(vector<int>& nums) { if(nums.size() == 0) return 0; int pos1 = 1; int repeat = 0; for(int i=1;i<nums.size();i++){ if(nums[i] == nums[i-1] && repeat == 1){ continue; }else if(nums[i] == nums[i-1] && repeat != 1){ ++repeat; }else{ repeat = 0; } nums[pos1++] = nums[i]; } return pos1; } };
3、排列问题
31. Next Permutation https://leetcode.com/problems/next-permutation/description/
void nextPermutation(vector<int>& nums) { int n = nums.size(), k, l; for (k = n - 2; k >= 0; k--) { if (nums[k] < nums[k + 1]) { break; } } if (k < 0) { reverse(nums.begin(), nums.end()); } else { for (l = n - 1; l > k; l--) { if (nums[l] > nums[k]) { break; } } swap(nums[k], nums[l]); reverse(nums.begin() + k + 1, nums.end()); } }
1、注意怎么将代码写得简单,第一次遍历的时候,从size()-1到0遍历,在结尾处判断是否小于0,如果使用while循环将条件写在一起,则判断条件也会更加复杂
2、如果给定的排列是最大的,则需要返回最小排列
3、第二次寻找的时候从尾部开始寻找,这样可以减少代码复杂度,因为从头部开始寻找的时候需要额外判断所有值比目的值都大的情况。
4、二分查找
注意二分查找的区间是[first, last],还是[first, last),两种区间的处理方式是不一样的,while循环中是否有等于也有影响,没有等于时当nums.size()==0时不能进入循环
二分查找的标准例子:
int binarysearch(vector<int>& nums, int target) { int left = 0; int right = nums.size() - 1; while (left <= right) { int middle = (left + right) / 2; if (nums[middle] == target) { return middle; } else if (nums[middle] < target) { left = middle + 1; } else { right = middle - 1; } }return -1; }
注意while循环在退出的时候left==right总是成立的
当数组中有重复元素的时候可以用二分查找来上下边界的情况
找上边界,尽量固定住右侧,即右侧发现相等元素时直接让right=middle,而不是middle-1,因为除2的情况下元素偏向左边,让左边加1就不会陷入死循环:
int left = 0; int right = nums.size()-1; while(left < right){ int middle = (left + right)/2; if(nums[middle]<target) left = middle+1; else right = middle; }
同理,寻找右边界的时候尽量固定住左边,让middle向右偏:
left = 0; right = nums.size()-1; while(left < right){ int middle = (left + right)/2 + 1; if(nums[middle] > target) right = middle -1; else left = middle+1; }
if(right<num.size() && data[right] !=target) right--;
但是此时退出状态有两种,pos2和pos1指向最后一个元素,或是pos2和pos1指向最后一个元素的下一个元素。所以再加上一个
if(pos2 <data.size() && data[pos2] != k) pos2 --;
33. Search in Rotated Sorted Array https://leetcode.com/problems/search-in-rotated-sorted-array/description/
int search(vector<int>& nums, int target) { int pos1 = 0; int pos2 = nums.size()-1; while(pos1 <= pos2){ int middle = (pos1+pos2)/2; if(nums[middle]== target){ return middle; }else if(nums[middle]>=nums[pos1]){ if(nums[middle] > target && nums[pos1] <= target){ pos2 = middle-1; }else{ pos1 = middle+1; } }else{ if(nums[middle] < target && nums[pos2] >= target){ pos1 = middle+1; }else{ pos2 = middle-1; } } } return -1; }
34. Find First and Last Position of Element in Sorted Array https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/description/
vector<int> searchRange(vector<int>& nums, int target) { if(nums.size() ==0) return {-1,-1}; int left = 0; int right = nums.size()-1; while(left < right){ int middle = (left + right)/2; if(nums[middle]<target) left = middle+1; else right = middle; } vector<int> result(2,-1); if(nums[left] == target) result[0] = left; else return result; left = 0; right = nums.size()-1; while(left < right){ int middle = (left + right)/2 + 1; if(nums[middle] > target) right = middle -1; else left = middle; } result[1] = left; return result; }
1、注意当数组长度为0的时候,找不到元素的时候这两种情况的边界条件
2、熟记二分查找寻找边界
81. Search in Rotated Sorted Array II https://leetcode.com/problems/search-in-rotated-sorted-array-ii/description/
1、最后一种情况的处理需要注意
153. Find Minimum in Rotated Sorted Array https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/
class Solution { public: int findMin(vector<int>& nums) { int pos1 = 0; int pos2 = nums.size()-1; while(pos1<pos2){ int middle = (pos1+pos2)/2; if(nums[pos1]<=nums[middle] && nums[middle]<nums[pos2]){ return nums[pos1]; }else if(nums[middle] < nums[pos2] && nums[pos2]<nums[pos1]){ pos2 = middle; }else{ pos1 = middle+1; } } return nums[pos1]; } };
209. Minimum Size Subarray Sum https://leetcode.com/problems/minimum-size-subarray-sum/description/
二分查找的思路,先使用一个单调递增的数列来存储开头到当前位置的长度和(数组项全为正数),每次使用二分法寻找第一个大于sum[i]+s的位置,也就是最小长度。代码写法可以好好的参考一下。
int n = nums.size(); if (n == 0) return 0; int ans = INT_MAX; vector<int> sums(n + 1, 0); //size = n+1 for easier calculations //sums[0]=0 : Meaning that it is the sum of first 0 elements //sums[1]=A[0] : Sum of first 1 elements //ans so on... for (int i = 1; i <= n; i++) sums[i] = sums[i - 1] + nums[i - 1]; for (int i = 1; i <= n; i++) { int to_find = s + sums[i - 1]; auto bound = lower_bound(sums.begin(), sums.end(), to_find); if (bound != sums.end()) { ans = min(ans, static_cast<int>(bound - (sums.begin() + i - 1))); } } return (ans != INT_MAX) ? ans : 0;
维护一个值大于s的序列,向前加一个数的时候,再从尾部减去直到序列小于s,然后又向前读取数组直到大于s
class Solution { public: int minSubArrayLen(int s, vector<int>& nums) { int result = INT_MAX; int pos = 0; int sum = 0; for(int i=0;i<nums.size();i++){ sum = sum + nums[i]; while(sum>=s){ result = min(i-pos+1,result); sum = sum - nums[pos++]; } } if(result == INT_MAX) return 0; return result; } };
1、边界条件当数组所有元素和都小于s的时候需要特殊处理
5、遍历数组
有很多遍历数组的题是使用遍历过程中将数组中的值置为负数来存储数据
35. Search Insert Position https://leetcode.com/problems/search-insert-position/description/
int searchInsert(vector<int>& nums, int target) { int pos = 0; for(size_t i = 0;i<nums.size();i++){ if(nums[i]<target) pos++; else return pos; } return pos; }
219. Contains Duplicate II https://leetcode.com/problems/contains-duplicate-ii/description/
class Solution { public: bool containsNearbyDuplicate(vector<int>& nums, int k) { map<int,int> map; for(int i=0;i<nums.size();i++){ if(map[nums[i]] != 0 && (i-map[nums[i]]+1)<=k) return true; else map[nums[i]] = i+1; } return false; } };
238. Product of Array Except Self https://leetcode.com/problems/product-of-array-except-self/description/
class Solution { public: vector<int> productExceptSelf(vector<int>& nums) { long long mul = 1; int zero = 0; for(int i=0;i<nums.size();i++){ if(nums[i] != 0){ mul = mul*nums[i]; }else{ zero++; } } vector<int> result(nums.size(),0); if(zero >= 2) return result; for(int i =0;i<result.size();i++){ if(zero !=0 && nums[i]!=0){ result[i] != 0; continue; }else if(zero !=0 && nums[i] == 0){ result[i] = mul; continue; } result[i] = mul/nums[i]; } return result; } };
1、关键在于能否想出0的情况
268. Missing Number https://leetcode.com/problems/missing-number/description/
class Solution { public: int missingNumber(vector<int>& nums) { sort(nums.begin(),nums.end()); for(int i=0;i<nums.size();i++){ if(nums[i] != i) return i; } return nums.size(); } };
1、优化方法、将所有值和0-9全部异或一遍,如果重复出现则一定清0、求和再相见
414. Third Maximum Number https://leetcode.com/problems/third-maximum-number/description/
class Solution { public: int thirdMax(vector<int>& nums) { long long m1 = (long long)INT_MIN - 1; long long m2 = (long long)INT_MIN - 2; long long m3 = (long long)INT_MIN - 3; int times = 0; for (int i = 0; i<nums.size(); i++) { if (nums[i]>m1) { times++; m3 = m2; m2 = m1; m1 = nums[i]; } else if (nums[i]<m1 && nums[i]>m2) { times++; m3 = m2; m2 = nums[i]; } else if (nums[i]<m2 && nums[i]>m3) { times++; m3 = nums[i]; } } if(times < 3) return m1; return m3; } };
1、如何处理越界的问题
442. Find All Duplicates in an Array https://leetcode.com/problems/find-all-duplicates-in-an-array/description/
class Solution { public: vector<int> findDuplicates(vector<int>& nums) { vector<int> res; for(int i = 0; i < nums.size(); i ++){ nums[abs(nums[i])-1] = -nums[abs(nums[i])-1]; if(nums[abs(nums[i])-1] > 0) res.push_back(abs(nums [i])); } return res; } };
巧妙的方法
448. Find All Numbers Disappeared in an Array https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/
class Solution { public: vector<int> findDisappearedNumbers(vector<int>& nums) { vector<int> result; for(int i=0;i<nums.size();i++){ int pos = abs(nums[i]) -1; nums[pos] = abs(nums[pos])*-1; } for(int i =0;i<nums.size();i++){ if(nums[i] >0) result.push_back(i+1); } return result; } };
同上的方法
495. Teemo Attacking https://leetcode.com/problems/teemo-attacking/description/
class Solution { public: int findPoisonedDuration(vector<int>& timeSeries, int duration) { if(timeSeries.size()==0) return 0; int pos1 = timeSeries[0]; int pos2 = timeSeries[0]; int result = 0; for(int i=1; i<timeSeries.size(); i++){ if(timeSeries[i]>timeSeries[i-1]+duration){ result = result + pos2 - pos1 + duration; pos1 = timeSeries[i]; pos2 = timeSeries[i]; }else{ pos2 = timeSeries[i]; } } return result + pos2 - pos1 + duration; } };
思路和合并区间那道题一样,忘了是哪题了,主要需要注意怎么简化代码
6、其他
寻找一个数组中最大子片段
53. Maximum Subarray https://leetcode.com/problems/maximum-subarray/description/
int maxSubArray(vector<int>& nums) { int max = INT_MIN; int current = 0; for(int i =0;i<nums.size();i++){ current = current + nums[i]; if(current > max) max = current; if(current < 0) current = 0; } return max; }
75. Sort Colors https://leetcode.com/problems/sort-colors/discuss/26474/Sharing-C++-solution-with-Good-Explanation
思路是维持两个位置,分别为0的结束位置和2的开始位置,遍历时如果碰到0则和前面的位置交换,碰到2则和后面的位置交换
void sortColors(vector<int>& nums) { int pos0 = 0; int pos1 = 0; int pos2 = nums.size()-1; while(pos1<=pos2){ if(nums[pos1] == 0){ swap(nums[pos0], nums[pos1]); ++pos0; ++pos1; }else if(nums[pos1] == 2){ swap(nums[pos1], nums[pos2]); --pos2; }else{ ++pos1; } } }
1、在mid和first交换的时候需要将mid和first同时++,而不是只++mid,因为在pos0到pos1这段是只有1的,因为0被交换到前面,2被交换到后面
119. Pascal's Triangle II https://leetcode.com/problems/pascals-triangle-ii/description/
class Solution { public: vector<int> getRow(int rowIndex) { vector<int> result(rowIndex+1,1); for(int i=3;i<=rowIndex+1;i++){ for(int j=i-2;j>0;j--){ result[j] = result[j]+result[j-1]; } } return result; } };
既然正向会覆盖,则逆向来赋值
120. Triangle https://leetcode.com/problems/triangle/description/
class Solution { public: int minimumTotal(vector<vector<int>>& triangle) { for(int i=triangle.size()-2;i>=0;i--){ for(int j=0;j<=i;j++){ triangle[i][j] = triangle[i][j] + min(triangle[i+1][j+1],triangle[i+1][j]); } } return triangle[0][0]; } };
动态规划,从底部可以简化代码很多
121. Best Time to Buy and Sell Stock https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/
class Solution { public: int maxProfit(vector<int>& prices) { if(prices.size()==0) return 0; int low = INT_MAX; int max = 0; for(int i=0;i<prices.size();i++){ if(prices[i]<low) low = prices[i]; if(prices[i]-low > max) max = prices[i]-low; } return max; } };
1、思路是遍历每一个位置的时候和前面的最小值相减
2、注意size等于0是为什么会错误
152. Maximum Product Subarray https://leetcode.com/problems/maximum-product-subarray/description/
class Solution { public: int maxProduct(vector<int>& nums) { if(nums.empty()) return 0; int maxMul=nums[0]; int minMul=nums[0]; int ans=nums[0]; for(int i=1;i<nums.size();i++) { int a = maxMul*nums[i]; int b = minMul*nums[i]; maxMul=max(max(a,b),nums[i]); minMul=min(min(a,b),nums[i]); ans=max(ans,maxMul); } return ans; } };
1、当累加值*当前值<当前值时可以更新位置
169. Majority Element https://leetcode.com/problems/majority-element/description/
class Solution { public: int majorityElement(vector<int>& nums) { int count = 0; int major = 0; for(int i=0;i<nums.size();i++){ if(count == 0){ count++; major = nums[i]; }else{ if(nums[i] == major){ count++; }else{ count--; } } } return major; } };
229. Majority Element II https://leetcode.com/problems/majority-element-ii/description/
class Solution { public: vector<int> majorityElement(vector<int>& nums) { vector<int> result; int major1 = 0; int major2 = 0; int count1 = 0; int count2 = 0; for(int i=0;i<nums.size();i++){ if(count1 != 0 && major1 == nums[i]){count1++;continue;} if(count2 != 0 && major2 == nums[i]){count2++;continue;} if(count1 == 0){major1 = nums[i];count1++;continue;} if(count2 == 0){major2 = nums[i];count2++;continue;} count1--; count2--; } int num1 = count1; int num2 = count2; count1 = 0; count2 = 0; for(int i=0;i<nums.size();i++){ if(num1>0){ if(nums[i] == major1) count1++; } if(num2>0){ if(nums[i] == major2) count2++; } } if(count1>nums.size()/3) result.push_back(major1); if(count2>nums.size()/3) result.push_back(major2); return result; } };
2题的思路一样,使用1个计数器或是2个计数器,遍历一个元素就从中删除其他两个元素的计数
217. Contains Duplicate https://leetcode.com/problems/contains-duplicate/description/
class Solution { public: bool containsDuplicate(vector<int>& nums) { sort(nums.begin(),nums.end()); for(int i =1;i<nums.size();i++){ if(nums[i] == nums[i-1]) return true; } return false; } };
228. Summary Ranges https://leetcode.com/problems/summary-ranges/description/
class Solution { public: vector<string> summaryRanges(vector<int>& nums) { vector<string> result; for(int i=0;i<nums.size();i++){ int begin = nums[i]; while(i != nums.size()-1 && nums[i]+1 == nums[i+1]){ i++; } int end = nums[i]; if(begin != end){ result.push_back(to_string(begin) + "->" + to_string(end)); }else{ result.push_back(to_string(begin)); } } return result; } };
二、复习
15
16
18
26
27
31
33
75
80
81
119
120
121
152
153
169
209
229
238
268
414
442
448
495