1. 程式人生 > >Divide and Conquer

Divide and Conquer

分治演算法

通常需要三個步驟

1.將原問題分解為一組子問題,每個子問題都與原問題型別相同,但是比原問題的規模小

2.遞迴求解這些子問題

3.將子問題的求解結果恰當合併,得到原問題的解

leetcode 53

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);
    }
};

leetcode 169

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;
    }
};

 

leetcode 215

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
    }   
};

leetcode 240

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;
    }
};

leetcode 241

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;
    }
};