分治算法
通常需要三个步骤
1.将原问题分解为一组子问题,每个子问题都与原问题类型相同,但是比原问题的规模小
2.递归求解这些子问题
3.将子问题的求解结果恰当合并,得到原问题的解
Given an integer array nums
, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
思路:
将数组分为左半边,中间元素,右半边。左半边数组中的最大和连续数组,右半边数组中的最大和连续数组,包含中间元素的当前数组的最大和连续数组,这三者当中和最大的数组就是当前数组的最大和连续数组。
class Solution {
public:
int getmax(vector<int>& nums, int l, int r){
if(l==r){
return nums[l];
}
int c = (l+r)/2;
int maxl = getmax(nums,l,c);
int maxr = getmax(nums,c+1,r);
int maxll = INT_MIN,maxrr=INT_MIN,ll=0,rr=0; //中间子序列左右半部分的最大值
for(int i = c;i>=l;i--){
ll+=nums[i];
maxll = max(maxll,ll);
}
for(int i = c+1;i<=r;i++){
rr+=nums[i];
maxrr = max(maxrr,rr);
}
int maxc = maxll+maxrr;
int maxnum = max(max(maxr,maxl),maxc);
return maxnum;
}
int maxSubArray(vector<int>& nums) {
return getmax(nums,0,nums.size()-1);
}
};
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋
times.
You may assume that the array is non-empty and the majority element always exist in the array.
思路:
将数组一分为二,分别求出两边的众数。合并时,如果两边众数一致,那么合并后的众数不变。如果不一致,就对两个数分别计算,比较数量多少,选出一个众数(如果相等,规定取一个,并不会影响最终的结果)。
class Solution {
public:
int majorityElement(vector<int>& nums) {
return handle(nums, 0, nums.size()-1);
}
int count(vector<int>& nums, int l, int r, int num) {
int c = 0;
for(int i = l; i <= r; i++)
if(nums[i] == num)
c++;
return c;
}
int handle(vector<int>& nums, int l, int r) {
if(l == r)
return nums[l];
int m = (l+r)/2;
int l_max = handle(nums, l, m);
int r_max = handle(nums, m+1, r);
if(l_max == r_max)
return l_max;
int l_count = count(nums, l, r, l_max);
int r_count = count(nums, l, r, r_max);
return l_count > r_count?l_max:r_max;
}
};
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
思路:
从数组中任意选定一个数v,将数组划分为三个部分:1.比v小的数,2.等于v的数,3.大于v的数, 如果k小于等于3的长度,就说明要找的元素在3那一段,如果k大于3的长度,但小于等于3+2的长度,说明要找的元素就是v,如果k大于3+2的长度,说明要找的元素在1那一段,之后就等价于在1里找第k-(2+3的长度)大的数了。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return handle(nums, k, 0, nums.size()-1);
}
void exchange(vector<int>& nums, int i ,int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
int handle(vector<int> &nums, int k, int l, int r) {
int lt = l, gt = r, v = nums[l];
for(int i = l; i <= r; i++)
if(nums[i] < v)
exchange(nums, lt++, i);
for(int i = r; i >= lt; i--)
if(nums[i] > v)
exchange(nums, gt--, i);
if(r-gt >= k)
return handle(nums, k, gt+1, r);
if(r-gt < k && r-lt+1 >= k)
return nums[lt];
if(r-lt+1 < k)
return handle(nums, k-(r-lt+1), l, lt-1); //确定好 +1 -1
}
};
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
- Integers in each row are sorted in ascending from left to right.
- Integers in each column are sorted in ascending from top to bottom
思路:
对于一个矩阵,左上角的数最小,右下角的数最大。将一个矩阵按田字分,可以快速排除不含该数字的子矩阵,然后对各个子问题进行进一步求解。
struct point {
int x;
int y;
};
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.size() == 0 || matrix[0].size() == 0)
return false;
return handle(matrix, {0,0}, {matrix[0].size()-1,matrix.size()-1}, target);
}
bool handle(vector<vector<int>>& matrix, point l, point r, int target) {
if(matrix[l.y][l.x] > target || matrix[r.y][r.x] < target)
return false;
// if(matrix[l.y][l.x] == target || matrix[r.y][r.x] == target)
// return true;
if(l.x == r.x && l.y == r.y)
return matrix[l.y][l.x] == target;
point m = {(l.x+r.x)/2,(l.y+r.y)/2};
if(handle(matrix,l,{m.x,m.y},target))
return true;
if(m.x+1 < matrix[0].size() && handle(matrix,{m.x+1,l.y},{r.x, m.y},target))
return true;
if(m.y+1 < matrix.size() && handle(matrix,{l.x,m.y+1},{m.x,r.y},target))
return true;
if(m.x+1 < matrix[0].size() && m.y+1 < matrix.size() && handle(matrix,{m.x+1,m.y+1},r,target))
return true;
return false;
}
};
Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +
, -
and *
.
思路:
对于一个包含n个运算符的算式,有n种方法使用括号将其变为两个”数“之间的运算,对于这两个“数“,又各自有他们包含的运算符的数量这么多种方法再进行相同的分解,最终分解为不包含运算符的算式。然后再将两边的所有可能进行运算,得到所有可能的结果。
class Solution {
public:
vector<int> diffWaysToCompute(string input) {
vector<int> v = handle(input);
std::sort(v.begin(),v.end());
return v;
}
vector<int> handle(string input) {
if(input.find('+') == string::npos && input.find('-') == string::npos && input.find('*') == string::npos)
return {atoi(input.c_str())};
vector<int> res;
for(int i = 0; i < input.length(); i++) {
if(input[i] == '+' || input[i] == '-' || input[i] == '*') {
vector<int> left = handle(input.substr(0,i));
vector<int> right = handle(input.substr(i+1,input.length()-i));
for(auto k:left)
for(auto j:right) {
if(input[i] == '+') {
res.push_back({k+j});
} else if(input[i] == '-') { // 注意i,j重复使用
res.push_back({k-j});
} else if(input[i] == '*') {
res.push_back({k*j});
}
}
}
}
return res;
}
};