1.Two Sum
naive
4.Median of Two Sorted Arrays
找两个已排序数组的中位数
直接数可以过,但很蠢,O(m+n)时间
1 class Solution { 2 public: 3 double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { 4 int p1=-1,p2=-1; 5 double rst = 0; 6 int len1 = nums1.size(),len2 = nums2.size(); 7 if (len1==0&&len2==0) return 0.0; 8 9 if ((len1+len2)%2==1) 10 { 11 int count=(len1+len2+1)/2; 12 if (len1==0) return 1.0*nums2[len2/2]; 13 if (len2==0) return 1.0*nums1[len1/2]; 14 while (count) 15 { 16 if (p1==len1-1) {rst=nums2[p2+1];p2++;} 17 else if (p2==len2-1) {rst=nums1[p1+1];p1++;} 18 else if (nums1[p1+1]>nums2[p2+1]) {rst=nums2[p2+1];p2++;} 19 else {rst=nums1[p1+1];p1++;} 20 count--; 21 } 22 return rst; 23 } 24 else { 25 int count=(len1+len2)/2; 26 if (len1==0) return 0.5*nums2[len2/2]+0.5*nums2[len2/2-1]; 27 if (len2==0) return 0.5*nums1[len1/2]+0.5*nums1[len1/2-1]; 28 int t1=0,t2=0; 29 while (count+1) 30 { 31 t1=t2; 32 if (p1==len1-1) {p2++;t2=nums2[p2];} 33 else if (p2==len2-1) {p1++;t2=nums1[p1];} 34 else if (nums1[p1+1]>nums2[p2+1]) {p2++;t2=nums2[p2];} 35 else {p1++;t2=nums1[p1];} 36 count--; 37 } 38 return 0.5*t1+0.5*t2; 39 } 40 } 41 };
Stupid
直接思路是二分,O(log (m+n))
1 class Solution { 2 public: 3 double findMedianSortedArrays(vector<int>& num1, vector<int>& num2) { 4 int size = num1.size() + num2.size(); 5 if (size % 2 == 1) return 1.0*search(num1, num2, 0, 0, size / 2 + 1); 6 else return 0.5*search(num1, num2, 0, 0, size / 2) + 0.5*search(num1, num2, 0, 0, size / 2 + 1); 7 } 8 private: 9 int _min(int a, int b) 10 { 11 return a>b ? b : a; 12 } 13 int search(vector<int>& nums1, vector<int>& nums2, int s1, int s2, int pos) 14 { 15 //TODO:nums1[s1,s1+1,...,m],nums2[s2,s2+1,...,n],find the "pos"th smallest number 16 if ((nums1.size() - s1)>(nums2.size() - s2)) 17 return search(nums2, nums1, s2, s1, pos); //use 1 extra call to ensure that nums1 is shorter 18 19 if (s1 == nums1.size()) 20 return nums2[s2 + pos-1]; 21 if (pos == 1) return _min(nums1[s1], nums2[s2]); //Point 1:边界特殊处理,否则RE 22 23 int k1 = _min(nums1.size() - s1, pos / 2); 24 int k2 = pos - k1; 25 26 if (nums1[s1 + k1 - 1] == nums2[s2 + k2 - 1]) //Point 2:等于的情况就不应该步进了 27 return nums1[s1 + k1 - 1]; 28 else if (nums1[s1 + k1 - 1] > nums2[s2 + k2 - 1]) 29 return search(nums1, nums2, s1, s2 + k2, pos - k2); 30 else 31 return search(nums1, nums2, s1 + k1, s2, pos - k1); 32 } 33 };
Binary Search
11.Container With Most Water
找h[i],h[j],使得min(h[i],h[j])*(j-i)最大
典型的双指针问题,从两端向中间逼近,注意移动条件
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int left = 0,right = height.size()-1; 5 int rst = 0; 6 while (left<right) 7 { 8 rst = _max(rst,(right-left)*_min(height[left],height[right])); 9 if (height[left]>height[right]) right--; //当h[l]>h[r]时,显然挪动左侧获得的结果不可能比此刻更好,因而挪右侧 10 else left++; //同理 11 } 12 return rst; 13 } 14 private: 15 int _min(int a,int b) 16 { 17 return a>b?b:a; 18 } 19 int _max(int a,int b) 20 { 21 return a>b?a:b; 22 } 23 };
15.3Sum
思路:先排序,之后对每一个小于0的数进行查询:
设num[i]<0,则b=i+1,c=num.size()-1,根据和的正/负/0向中间逼近
注意:1.去重 2.数组越界 3.终止条件(当num[i]>0时,由于已排序,后面不必再扫)
1 class Solution { 2 public: 3 vector<vector<int>> threeSum(vector<int>& nums) { 4 vector<vector<int>> rst; 5 if (nums.size()<3) return rst; 6 sort(nums.begin(), nums.end()); 7 int i = 0, a = nums[i]; 8 while (i<=nums.size()-3) 9 { 10 int b = i + 1, c = nums.size() - 1; 11 while (b<c) { 12 int l = nums[b], r = nums[c]; 13 if (nums[i] + nums[b] + nums[c] == 0) 14 { 15 vector<int> t({ nums[i],nums[b],nums[c] }); 16 rst.push_back(t); 17 while ((b<nums.size())&&(nums[b] == l)) b++; 18 while ((c>=0)&&(nums[c] == r)) c--; 19 } 20 else if (nums[i] + nums[b] + nums[c]<0) { while ((b<nums.size()) && (nums[b] == l)) b++; } 21 else { while ((c>=0) && (nums[c] == r)) c--; } 22 } 23 while ((i<=nums.size()-3)&&(nums[i] == a)) i++; 24 a = nums[i]; 25 } 26 return rst; 27 } 28 };
16.3Sum Closest
思路:不需要去重,直接双指针找即可,比15简单
1 class Solution { 2 public: 3 int threeSumClosest(vector<int>& nums, int target) { 4 if (nums.size()<3) return -1; //undefined 5 sort(nums.begin(), nums.end()); 6 int rst = 0x3f3f3f3f; 7 int a = 0, b, c; 8 while (a <= nums.size() - 3) { 9 b = a + 1, c = nums.size() - 1; 10 int l = nums[b], r = nums[c], t = nums[a]; 11 while (b<c) 12 { 13 int temp = nums[a] + l + r; 14 if (abs(temp - target)<abs(rst - target)) 15 rst = temp; 16 if (temp>target) { c--; } 17 else { b++; } 18 l = nums[b]; 19 r = nums[c]; 20 } 21 if (rst == target) break; 22 a++; 23 } 24 return rst; 25 } 26 };
18.4Sum
思路:naive:对每个元素搞一次3Sum
优化思路:剪枝:当有两个点已确定时,在循环开始之前先判断最小的两个数加起来是否已经超过要求;最大的两个数加起来是否仍不足
1 class Solution { 2 public: 3 vector<vector<int>> fourSum(vector<int>& nums, int target) { 4 vector<vector<int>> rst; 5 if (nums.size()<4) return rst; 6 sort(nums.begin(), nums.end()); 7 int s = 0, start = nums[s]; 8 while (s <= nums.size() - 4) 9 { 10 int tar = target - start; 11 int i = s + 1, a = nums[i]; 12 while (i <= nums.size() - 3) 13 { 14 int b = i + 1, c = nums.size() - 1; 15 while (b<c) { 16 int l = nums[b], r = nums[c]; 17 if (nums[i] + nums[b] + nums[c] == tar) 18 { 19 vector<int> t({ nums[s],nums[i],nums[b],nums[c] }); 20 rst.push_back(t); 21 while ((b<nums.size()) && (nums[b] == l)) b++; 22 while ((c >= 0) && (nums[c] == r)) c--; 23 } 24 else if (nums[i] + nums[b] + nums[c]<tar) { 25 while ((b<nums.size()) && (nums[b] == l)) b++; 26 } 27 else { while ((c >= 0) && (nums[c] == r)) c--; } 28 } 29 while ((i <= nums.size() - 3) && (nums[i] == a)) i++; 30 a = nums[i]; 31 } 32 while ((s <= nums.size() - 4) && (nums[s] == start)) s++; 33 start = nums[s]; 34 } 35 return rst; 36 } 37 };
Naive
1 class Solution { 2 public: 3 vector<vector<int>> fourSum(vector<int>& nums, int target) { 4 vector<vector<int>> rst; 5 if (nums.size()<4) return rst; 6 sort(nums.begin(), nums.end()); 7 for (int i = 0; i < nums.size() - 3; i++) 8 { 9 if ((i > 0) && (nums[i] == nums[i - 1])) continue; 10 int t1 = target - nums[i]; 11 for (int j = i + 1; j < nums.size() - 2; j++) 12 { 13 if ((j > i + 1) && (nums[j] == nums[j - 1])) continue; 14 int t2 = t1 - nums[j]; 15 int k = j + 1, r = nums.size() - 1; 16 if (nums[k] + nums[k + 1]>t2) break; 17 if (nums[r - 1] + nums[r] < t2) continue; 18 while (k < r) 19 { 20 if (nums[k] + nums[r] == t2) 21 { 22 rst.push_back({ nums[i],nums[j],nums[k],nums[r] }); 23 k++; r--; 24 while ((k<r) && (nums[k] == nums[k - 1]))k++; 25 while ((k<r) && (nums[r] == nums[r + 1]))r--; 26 } 27 else if (nums[k] + nums[r] < t2) 28 { 29 k++; 30 } 31 else 32 r--; 33 } 34 } 35 } 36 return rst; 37 } 38 };
加优化
26.Remove Duplicates from Sorted Array
去重,简单题,注意返回值是数组长度
1 class Solution { 2 public: 3 int removeDuplicates(vector<int>& nums) { 4 if (nums.size()==0) return 0; 5 int p=0; 6 for (int i=1;i<nums.size();i++) 7 { 8 if (nums[i]!=nums[i-1]) nums[++p]=nums[i]; 9 } 10 return p+1; 11 } 12 };
31.Next Permutation
基础题
算法:初始化:i=0,ii=0,j=0
1.从后向前扫,找到第一对相邻的nums[i]<nums[ii],ii=i+1;
2.从后向前扫,找到第一个大于nums[i]的nums[j]
3.交换nums[i],num[j],并将ii及之后的数组反转
1 从后向前扫,显然递减序列是最“大”的排列,因此找到非递减序列的开始 2 第一步后:nums[ii-end]为递减序列,此时将i与nums[ii-end]中的任意一个数交换,都可以保证其为此序列之后的序列(但不一定就是下一个) 3 为了保证是下一个,找到最小的大于i的数,交换 4 注意到交换后ii后面仍为有序序列,为了使得交换后该子序列最“小”,反转该序列即可
证明
1 class Solution { 2 public: 3 void nextPermutation(vector<int>& nums) { 4 int i=0,ii=0,j=0; 5 for (int k=nums.size()-1;k>0;k--) 6 { 7 if (nums[k-1]<nums[k]) { 8 i=k-1;ii=k;break; 9 } 10 } 11 for (int k=nums.size()-1;k>0;k--) 12 { 13 if (nums[k]>nums[i]) {j=k;break;} 14 } 15 swap(nums,i,j); 16 reverse(nums,ii,nums.size()-1); 17 } 18 private: 19 void swap(vector<int>& nums,int a,int b) 20 { 21 int t=nums[a]; 22 nums[a]=nums[b]; 23 nums[b]=t; 24 } 25 void reverse(vector<int>& nums,int start,int end) 26 { 27 int p=start,q=end; 28 while (p<q) 29 { 30 swap(nums,p,q); 31 p++;q--; 32 } 33 } 34 };
扩展:
1.已知有序数组{a_1,a_2,...,a_n},求第k个排列
第一位后面有(n-1)!种排列,因而第一位的数字应为a[k/(n-1)!],剩余k%(n-1)!种情况
依次确认之后每一位的排列即可
举例说明:如7个数的集合为{1, 2, 3, 4, 5, 6, 7},要求出第n=1654个排列。
(1654 / 6!)取整得2,确定第1位为3,剩下的6个数{1, 2, 4, 5, 6, 7},求第1654 % 6!=214个序列;
(214 / 5!)取整得1,确定第2位为2,剩下5个数{1, 4, 5, 6, 7},求第214 % 5!=94个序列;
(94 / 4!)取整得3,确定第3位为6,剩下4个数{1, 4, 5, 7},求第94 % 4!=22个序列;
(22 / 3!)取整得3,确定第4位为7,剩下3个数{1, 4, 5},求第22 % 3!=4个序列;
(4 / 2!)得2,确定第5为5,剩下2个数{1, 4};由于4 % 2!=0,故第6位和第7位为增序<1 4>;
因此所有排列为:3267514。
(60.Permutation Sequence
class Solution { public: string getPermutation(int n, int k) { vector<int> vec; for (int i=0;i<n;i++) vec.push_back(i); string str; int rank = k-1; for (int i=0;i<n;i++) { int cas = fact(n-i-1); int temp = rank/cas; rank = rank%cas; str+=(‘1‘+vec[temp]); vec.erase(vec.begin()+temp); } return str; } private: int fact(int n) { int rst=1; while (n>0) {rst*=n;n--;} return rst; } };
注意:数组从0开始还是从1开始)
2.已知一个排列{a_1,a_2,...,a_n},求这是第几个排列
反过来求即可:
第一位序数为k_1,则排列至少为第(k_1-1)*(n-1)!个
依此类推即可
例如3267514:
后6位的全排列为6!,3为{1, 2, 3 ,4 , 5, 6, 7}中第2个元素(从0开始计数),故2*720=1440;
后5位的全排列为5!,2为{1, 2, 4, 5, 6, 7}中第1个元素,故1*5!=120;
后4位的全排列为4!,6为{1, 4, 5, 6, 7}中第3个元素,故3*4!=72;
后3位的全排列为3!,7为{1, 4, 5, 7}中第3个元素,故3*3!=18;
后2位的全排列为2!,5为{1, 4, 5}中第2个元素,故2*2!=4;
最后2位为增序,因此计数0,求和得:1440+120+72+18+4=1654
参考:http://www.cnblogs.com/devymex/archive/2010/08/17/1801122.html
(46. Permutations
输出给定无重复数组的全排列
不要脸的做法:next_permutation,效率高于一般的递归,但仍较低(理论上(n*n!))
一般的做法:递归:理论上为O(n!),实际上优化的好坏与结果关系很大)
1 class Solution { 2 public: 3 vector<vector<int>> permute(vector<int>& nums) { 4 vector<vector<int>> rst; 5 if (nums.size() == 0) return rst; 6 allPermute(nums, 0, nums.size() - 1, rst); 7 return rst; 8 } 9 private: 10 vector<vector<int>> allPermute(vector<int>& nums, int k, int len, vector<vector<int>> &rst) 11 { 12 if (k == len) { 13 vector<int> vec; 14 for (int i = 0; i < nums.size(); i++) 15 vec.push_back(nums[i]); 16 rst.push_back(vec); 17 } 18 else { 19 for (int i = k; i <= len; i++) 20 { 21 int temp = nums[k]; 22 nums[k] = nums[i]; 23 nums[i] = temp; 24 allPermute(nums, k + 1, len, rst); 25 int temp1 = nums[k]; 26 nums[k] = nums[i]; 27 nums[i] = temp1; 28 } 29 } 30 return rst; 31 } 32 };
1 class Solution { 2 public: 3 vector<vector<int>> permute(vector<int>& nums) { 4 vector<vector<int>> rst; 5 allPermute(nums, 0, rst); 6 return rst; 7 } 8 private: 9 void allPermute(vector<int>& nums, int start, vector<vector<int>>& rst) 10 { 11 if (start >= nums.size()-1) rst.push_back(nums); 12 else { 13 for (int i = start; i <= nums.size() - 1; i++) 14 { 15 swap(nums[i], nums[start]); 16 allPermute(nums, start + 1, rst); 17 swap(nums[i], nums[start]); 18 } 19 } 20 } 21 };
72.27%
33. Search in Rotated Sorted Array
思路:首先找到转折点,之后在两边分别二分搜索,总的复杂度仍为O(logn)
1 class Solution { 2 public: 3 int search(vector<int>& nums, int target) { 4 int pivot = searchPivot(nums,0,nums.size()-1); 5 int rst = Search(nums,target,0,pivot); 6 if (rst == -1) rst = Search(nums,target,pivot+1,nums.size()-1); 7 return rst; 8 } 9 private: 10 int searchPivot(vector<int>& nums,int start,int end) 11 { 12 int p = start+(end-start)/2; 13 if (p==start) return p; 14 if (nums[p]>nums[start]) return searchPivot(nums,p,end); 15 else return searchPivot(nums,start,p); 16 } 17 int Search(vector<int>& nums,int target,int start,int end) 18 { 19 if (target>nums[end]||target<nums[start]||start>end) return -1; 20 else { 21 int pivot = start+(end-start)/2; 22 if (nums[pivot]==target) return pivot; 23 else if (nums[pivot]>target) return Search(nums,target,start,pivot-1); 24 else if (nums[pivot]<target) return Search(nums,target,pivot+1,end); 25 } 26 } 27 };
34. Search for a Range
简单题,二分找到点后扩一下即可
1 class Solution { 2 public: 3 vector<int> searchRange(vector<int>& nums, int target) { 4 int i = Search(nums,target,0,nums.size()-1); 5 vector<int> rst; 6 if (i==-1) 7 { 8 rst.push_back(-1); 9 rst.push_back(-1); 10 } 11 else { 12 int s=i,e=i; 13 while (s>0 && nums[s-1]==nums[s]) s--; 14 while (e<nums.size()-1 && nums[e+1]==nums[s]) e++; 15 rst.push_back(s); 16 rst.push_back(e); 17 } 18 return rst; 19 } 20 private: 21 int Search(vector<int>& nums,int target,int start,int end) 22 { 23 if (start>end) return -1; 24 else { 25 int pivot = start+(end-start)/2; 26 if (nums[pivot]==target) return pivot; 27 else if (nums[pivot]>target) return Search(nums,target,start,pivot-1); 28 else if (nums[pivot]<target) return Search(nums,target,pivot+1,end); 29 } 30 } 31 32 };
35. Search Insert Position
简单题,此处在找不到该值时,返回start而非-1即可,之后对start进行处理,找到需要的位置
1 class Solution { 2 public: 3 int searchInsert(vector<int>& nums, int target) { 4 int rst = Search(nums,target,0,nums.size()-1); 5 if (nums[rst]>target) 6 { 7 while (rst>0 && nums[rst-1]>target) rst--; 8 } 9 else if (nums[rst]<target) 10 { 11 while (rst<nums.size()-1 && nums[rst+1]<target) rst++; 12 } 13 return rst; 14 } 15 private: 16 int Search(vector<int>& nums,int target,int start,int end) 17 { 18 if (start>end) return start; 19 else { 20 int pivot = start+(end-start)/2; 21 if (nums[pivot]==target) return pivot; 22 else if (nums[pivot]>target) return Search(nums,target,start,pivot-1); 23 else if (nums[pivot]<target) return Search(nums,target,pivot+1,end); 24 } 25 } 26 };
39. Combination Sum
简单回溯题,注意去重时的操作
1 class Solution { 2 public: 3 vector<vector<int>> combinationSum(vector<int>& candidates, int target) { 4 sort(candidates.begin(), candidates.end()); 5 vector<vector<int>> rst; 6 vector<int> cas; 7 Find(cas, candidates, target, rst); 8 return rst; 9 } 10 private: 11 void Find(vector<int>& sol, vector<int>& candidates, int target, vector<vector<int>>& rst) 12 { 13 if (target == 0) { rst.push_back(sol); return; } 14 for (int i = 0; i < candidates.size(); i++) 15 { 16 if (sol.size()>0 && (sol.back()) > candidates[i]) continue; //此处要谨慎,不能和下面的if合并,否则遇到一个不符合条件的就直接break 17 if (target >= candidates[i]) 18 { 19 sol.push_back(candidates[i]); 20 Find(sol, candidates, target - candidates[i], rst); 21 sol.pop_back(); 22 } 23 else break; 24 } 25 return; 26 } 27 };
40. Combination Sum II
在39的基础上,给定的数字有重复,但每个数字只能用一次
思路:在39的基础上加一个数组记录某个特定数字最多可用几次,额外开销为O(n)
1 class Solution { 2 public: 3 vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { 4 vector<vector<int>> rst; 5 if (candidates.size()==0) return rst; 6 sort(candidates.begin(), candidates.end()); 7 vector<int> flag,candi; 8 candi.push_back(candidates[0]); 9 flag.push_back(1); 10 int p = 0; 11 for (int i=1;i<candidates.size();i++) 12 { 13 if (candidates[i-1]<candidates[i]) //注意去重条件 14 { 15 candi.push_back(candidates[i]); 16 flag.push_back(1); 17 p++; 18 } 19 else { 20 flag[p]++; 21 } 22 } 23 vector<int> cas; 24 Find(cas, candi, target, rst,flag); 25 return rst; 26 } 27 private: 28 void Find(vector<int>& sol, vector<int>& candidates, int target, vector<vector<int>>& rst,vector<int>& flag) 29 { 30 if (target == 0) { rst.push_back(sol); return; } 31 for (int i = 0; i < candidates.size(); i++) 32 { 33 if (!flag[i]) continue; 34 if ((sol.size()>0) && (sol.back() > candidates[i])) continue; //此处要谨慎,不能和下面的if合并,否则遇到一个不符合条件的就直接break 35 if (target >= candidates[i]) 36 { 37 flag[i]--; 38 sol.push_back(candidates[i]); 39 Find(sol, candidates, target - candidates[i], rst,flag); 40 sol.pop_back(); 41 flag[i]++; 42 } 43 else break; 44 } 45 return; 46 } 47 };