zoukankan      html  css  js  c++  java
  • A 第四课 递归_回溯_分治

    内容概述及预备知识

    预备知识:递归函数与回溯算法

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class ListNode{
    public:
    int val;
    ListNode * next;
    ListNode(int x):val(x),next(NULL){
    }
    };
    // 将 链表中的 数据递归加入到 vector 中
    void addToVec(ListNode* header,vector<int>& vec){
    // 递归条件
    if(header == NULL){
    return;
    }
    vec.push_back(header->val);
    // 递归链条
    addToVec(header->next,vec);
    }
    
    int main(){
    ListNode a(1);
    ListNode b(2);
    ListNode c(3);
    ListNode d(4);
    ListNode e(5);
    
    a.next = &b; // 链接 链表
    b.next = &c;
    c.next = &d;
    d.next = &e;
    
    vector<int> vec;
    addToVec(&a,vec);
    
    // 遍历 vec
    for(auto it=vec.cbegin();it!=vec.cend();it++){
    cout << *it << " ";
    }
    cout << endl;
    
    return 0;
    }
    递归小练习(结合链表)

    回溯法:

    回溯一般要用递归来实现,

    例1-a:求子集(LeetCode No.78 )

    给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    说明:解集不能包含重复的子集。

    示例:

    输入: nums = [1,2,3]
    输出:
    [
    [3],
      [1],
      [2],
      [1,2,3],
      [1,3],
      [2,3],
      [1,2],
      []
    ]

    思路及代码

    1,循环,不容易往后退, 

    2, 如何生成  [1] ,[1,2]  [1,2,3] ,

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main(){
    vector<int> nums;
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(3);
    
    
    // 生成item :type is vector<int>
    int size = nums.size();
    vector<int> item;
    vector<vector<int>> result;
    for(int i=0;i<size;i++){
    item.push_back(nums[i]);
    result.push_back(item);
    }
    // 打印 result
    for(auto it= result.cbegin();it!=result.cend();it++){
    for(auto it2 = (*it).cbegin();it2!=(*it).cend();it2++){
    cout << *it2<<" ";
    }
    cout << endl;
    }
    
    return 0;
    }
    /*
    1
    1 2
    1 2 3
    */
    循环生成
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void generate(int idx,vector<int>& nums,vector<int>& item,vector<vector<int>>& result){
    
    // 递归条件
    if(idx > (int)nums.size() - 1){
    return;
    }
    item.push_back(nums[idx]);
    result.push_back(item);
    // 递归链条
    generate(idx+1,nums,item,result);
    return;
    }
    
    int main(){
    vector<int> nums;
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(3);
    
    vector<int> item;
    vector<vector<int>> result;
    
    // 递归生成 result
    generate(0,nums,item,result);
    
    // 打印 result
    for(auto it= result.cbegin();it!=result.cend();it++){
    for(auto it2 = (*it).cbegin();it2!=(*it).cend();it2++){
    cout << *it2<<" ";
    }
    cout << endl;
    }
    
    return 0;
    }
    /*
    1
    1 2
    1 2 3
    */
    递归生成

    算法思路:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    
    void generate(int idx,vector<int>nums,vector<int>& item,vector<vector<int>>& res){
    
    // 递归条件
    if(idx > (int)nums.size() -1){
    return;
    }
    item.push_back(nums[idx]);
    res.push_back(item);
    
    // 递归链条 (第一次递归)
    generate(idx+1,nums,item,res);
    item.pop_back();
    // 递归链条 (第二次递归)
    generate(idx+1,nums,item,res);
    
    }
    
    
    vector<vector<int>> subsets(vector<int>& nums) {
    
    vector<int> item;
    vector<vector<int>> res;
    res.push_back(item); // 将空集 push 进去
    generate(0,nums,item,res);
    
    return res;
    }
    
    int main(){
    vector<int> nums;
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(3);
    nums.push_back(4);
    
    vector<vector<int>> ret = subsets(nums);
    
    
    
    
    // 打印 ret
    for(auto it= ret.cbegin();it!=ret.cend();it++){
    for(auto it2 = (*it).cbegin();it2!=(*it).cend();it2++){
    cout << *it2<<" ";
    }
    cout << endl;
    }
    return 0;
    }
    View Code

    方法二:位运算法:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    vector<vector<int>> subsets(vector<int>& nums) {
    
    vector<vector<int>> res;
    int size = nums.size();
    int totalNum = 1 << size; // 1<< n 即 2^n
    for(int i=0;i<totalNum;i++){
    vector<int> item;
    for(int j= 0;j<size;j++){ // 遍历nums中元素,
    // 使用元素对应的整数 和 i 比较
    if(i & 1<<(size - j - 1)){ // [a,b,c] // a:100 b:100 c:001
    item.push_back(nums[j]);
    }
    }
    res.push_back(item);
    }
    
    return res;
    }
    
    int main(){
    vector<int> nums;
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(3);
    
    vector<vector<int>> ret = subsets(nums);
    
    // 打印 ret
    for(auto it= ret.cbegin();it!=ret.cend();it++){
    for(auto it2 = (*it).cbegin();it2!=(*it).cend();it2++){
    cout << *it2<<" ";
    }
    cout << endl;
    }
    return 0;
    }
    View Code

    例1-b:求子集2(LeetCode No.90)

    给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    说明:解集不能包含重复的子集。

    示例:

    输入 nums = [1,2,2] 

     按上面的算法结果是:

    1
    1 2
    1 2 2
    1 2
    2
    2 2
    2

    注意:结果中1,2  和 1,2 重复, 

    思考和代码:

    #include <iostream>
    #include <set>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    
    void generate(int idx,vector<int>nums,vector<int>& item,vector<vector<int>>& res,set<vector<int>> & res_set){
    
        // 递归条件
        if(idx > (int)nums.size() -1){
            return;
        }
        item.push_back(nums[idx]);
        if(res_set.find(item) == res_set.end()){ // 如果 在res_set 中 不能找到 item 
            res.push_back(item);
            res_set.insert(item);
        }
        
        // 递归链条 (第一次递归)
        generate(idx+1,nums,item,res,res_set);
        item.pop_back();
        // 递归链条 (第二次递归)
        generate(idx+1,nums,item,res,res_set);
    
    }
    
    
    vector<vector<int>> subsets(vector<int>& nums) {
    
        vector<int> item;
        vector<vector<int>> res;
        set<vector<int>> res_set; // 去重用的集合
        sort(nums.begin(),nums.end()); // 排序 
    
        res.push_back(item); // 将空集 push 进去
        generate(0,nums,item,res,res_set);
    
    return res;
    }
    
    int main(){
    vector<int> nums;
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(2);
    
    vector<vector<int>> ret = subsets(nums);
    
    
    
    
    // 打印 ret
    for(auto it= ret.cbegin();it!=ret.cend();it++){
    for(auto it2 = (*it).cbegin();it2!=(*it).cend();it2++){
    cout << *it2<<" ";
    }
    cout << endl;
    }
    return 0;
    }
    View Code

    例1-c:组合数之和2(LeetCode No.40)

    思路及代码

    #include <iostream>
    #include <set>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    
    void generate(int idx,vector<int>nums,vector<int>& item,vector<vector<int>>& res,set<vector<int>> & res_set){
    
        // 递归条件
        if(idx > (int)nums.size() -1){
            return;
        }
        item.push_back(nums[idx]);
        if(res_set.find(item) == res_set.end()){ // 如果 在res_set 中 不能找到 item 
            res.push_back(item);
            res_set.insert(item);
        }
        
        // 递归链条 (第一次递归)
        generate(idx+1,nums,item,res,res_set);
        item.pop_back();
        // 递归链条 (第二次递归)
        generate(idx+1,nums,item,res,res_set);
    
    }
    
    
    vector<vector<int>> subsets(vector<int>& nums,int target) {
    
        vector<int> item;
        vector<vector<int>> res;
        set<vector<int>> res_set; // 去重用的集合
        sort(nums.begin(),nums.end()); // 排序 
    
        res.push_back(item); // 将空集 push 进去
        generate(0,nums,item,res,res_set);
    
        vector<vector<int>> target_res; // 存储最终的结果 
        for(int i=0;i<(int)res.size();i++){
            int sum = 0;
            for(int j =0;j<(int)res[i].size();j++){
                sum += res[i][j];
            }
            if(sum == target){
                target_res.push_back(res[i]);
            }
        }
        return target_res;
    }
    
    int main(){
    vector<int> nums;
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(2);
    
    vector<vector<int>> ret = subsets(nums);
    
    
    
    
    // 打印 ret
    for(auto it= ret.cbegin();it!=ret.cend();it++){
    for(auto it2 = (*it).cbegin();it2!=(*it).cend();it2++){
    cout << *it2<<" ";
    }
    cout << endl;
    }
    return 0;
    }
    在1-b 的基础上,提交超时

    如何解决上面的问题,通过剪枝

    #include <iostream>
    #include <vector>
    #include <set>
    #include <algorithm>
    using namespace std;
    
    void generate(int idx,vector<int>& nums,vector<int>& item,vector<vector<int>>& res,set<vector<int>>& res_set,int sum,int target){
        int size = nums.size();
        // base case 
        if(idx > size -1 || sum > target){
            return;
        }
        item.push_back(nums[idx]);
        sum += nums[idx];
        
        if(sum == target && res_set.find(item) == res_set.cend()){ // 在res_set 中没找到 item
            res_set.insert(item);
            res.push_back(item);
        }
    
        // 递归链条(第一次)
        generate(idx+1,nums,item,res,res_set,sum,target);
        item.pop_back(); // 回溯 
        sum -= nums[idx];
    
        // 递归链条(第一次)
        generate(idx+1,nums,item,res,res_set,sum,target);
    }
    
    vector<vector<int>> subsets(vector<int>& nums,int target){
        sort(nums.begin(),nums.end());
    
        vector<int> item;
        vector<vector<int>> res;
        set<vector<int>> res_set;
    
        generate(0,nums,item,res,res_set,0,target);
    
        return res;
    }
    
    
    int main(){
        vector<int> nums;
        nums.push_back(1);
        nums.push_back(3);
        nums.push_back(2);
    
        vector<vector<int>> ret;
        ret = subsets(nums,4);
    
        // 打印
        for(auto it1 = ret.cbegin();it1!=ret.cend();it1++){
            for(auto it2 = (*it1).cbegin();it2!=(*it1).cend();it2++){
                cout <<*it2<<" ";
            }
            cout << endl;
        }
    
    
    
    
        return 0;
    }
    View Code

    例2:生成括号(LeetCode No.22)

    数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

    示例:

    输入:n = 3
    输出:[
    "((()))",
    "(()())",
    "(())()",
    "()(())",
    "()()()"
    ]

    思路及代码

    思考:

    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    
    void generate(string item,int n,vector<string>& res){
        // base case 
        int size= item.size();
        if(size == 2*n){
            res.push_back(item);
            return;
        }
    
        // 递归链条 
        generate(item+"(",n,res);
        generate(item+")",n,res);
    
    }
    
    int main(){
    
        vector<string> ret;
    
        generate("",2,ret); //2 组括号 
    
        for(auto it=ret.cbegin();it!=ret.cend();it++){
            cout << *it << endl;
        }
    
    
        return 0;
    }
    
    /* output
    ((((
    ((()
    (()(
    (())
    ()((
    ()()
    ())(
    ()))
    )(((
    )(()
    )()(
    )())
    ))((
    ))()
    )))(
    ))))
    
    */
    View Code

    合法性:

    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    
    void generate(string item,int n,vector<string>& res,int lfNum,int rtNum){ // lf rt为 左右括号的个数
        // base case 
        int size= item.size();
        if(lfNum > n || rtNum >n){ // 肯定是不合法的 
            return;
        }
        if(size == 2*n){
            res.push_back(item);
            return;
        }
    
        // 递归链条 
        generate(item+"(",n,res,lfNum+1,rtNum);
    
        if(lfNum > rtNum){ // 此时才能进行 右括号的添加
            generate(item+")",n,res,lfNum,rtNum+1);
        }
    
    }
    
    int main(){
    
        vector<string> ret;
    
        generate("",2,ret,0,0); //2 组括号 
    
        for(auto it=ret.cbegin();it!=ret.cend();it++){
            cout << *it << endl;
        }
    
    
        return 0;
    }
    我的代码
    class Solution {
    private:
    void generate(string item,int lfNum,int rtNum,vector<string>& res){ // lf rt为 当前还可以放置的数量 
    
    
        if(lfNum == 0 && rtNum == 0){
            res.push_back(item);
            return;
        }
        if(lfNum >0){
            generate(item+"(",lfNum-1,rtNum,res);
        }
        if(lfNum<rtNum){
            generate(item+")",lfNum,rtNum-1,res);
        }
    
    }
    public:
        vector<string> generateParenthesis(int n) {
          vector<string> ret;
          generate("",n,n,ret);
          return ret;
        }
    };
    ls 代码

    例3:N皇后(LeetCode No.51)

    思路及代码

    皇后的攻击范围:

    棋盘和皇后表示:

    放完皇后如何更新棋盘?(通过方向数组解决)

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void put_down_the_queen(int x,int y,vector<vector<int>>& mark){
        // 方向数组 
        static const int dx[] = {-1,1,0,0,-1,-1,1,1};// dx 和dy 要对应
        static const int dy[] = {0,0,-1,1,-1,1,-1,1};
    
        mark[x][y] = 1;
        int size = mark.size();
        for(int i=1;i<size;i++){
    
            for(int j=0;j<8;j++){
                int newX = x+i*dx[j];
                int newY = y+i*dy[j];
                if(newX>=0&&newX<size && newY>=0&&newY<size){
                    mark[newX][newY] = 1;
                }
            }
        }
    
    }
    
    
    
    void myPrint(vector<vector<int>> mark){
        for(int i=0;i<8;i++){
            for(int j=0;j<8;j++){
                cout <<mark[i][j]<< " ";
            }
            cout << endl;
        }
    
    }
    
    int main(){
        vector<vector<int>> mark;
        // 生成 mark  
        vector<int> temp;
        for(int i=0;i<8;i++){
            for(int j=0;j<8;j++){
                temp.push_back(0);
            }
            mark.push_back(temp);
            temp.clear();
        }
    
        // 打印 mark  
        myPrint(mark);
        cout << "======put the queen to the pos(3,2)====="<< endl;
        
        // 放置皇后, 更新 mark 
        put_down_the_queen(3,2,mark); // 放在 4行 3列
    
        // 打印 mark  
        myPrint(mark);
    
    
        return 0;
    }
    
    /* output:
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    ======put the queen to the pos(3,2)=====
    0 0 1 0 0 1 0 0 
    1 0 1 0 1 0 0 0 
    0 1 1 1 0 0 0 0 
    1 1 1 1 1 1 1 1 
    0 1 1 1 0 0 0 0 
    1 0 1 0 1 0 0 0 
    0 0 1 0 0 1 0 0 
    0 0 1 0 0 0 1 0 
    */
    View Code

    算法思路:

    用递归放皇后到每一行,然后回溯列(放在该列,完成后再尝试不放在该列)

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void put_down_the_queen(int x,int y,vector<vector<int>>& mark){
        // 方向数组 
        static const int dx[] = {-1,1,0,0,-1,-1,1,1};// dx 和dy 要对应
        static const int dy[] = {0,0,-1,1,-1,1,-1,1};
    
        mark[x][y] = 1;
        int size = mark.size();
        for(int i=1;i<size;i++){
            for(int j=0;j<8;j++){
                int newX = x+i*dx[j];
                int newY = y+i*dy[j];
                if(newX>=0&&newX<size && newY>=0&&newY<size){
                    mark[newX][newY] = 1;
                }
            }
        }
    
    }
    void generate(int idx,int n,vector<string>& item,vector<vector<string>>& res,vector<vector<int>>& mark){ // 放置idx 皇后 ,总共n个皇后 
    
        // base case  
        if(idx > n-1){
            res.push_back(item);
            return;
        }
    
        // 一一尝试 n 列 
        for(int i=0;i<n;i++){
            if(mark[idx][i] == 0){ // 此时可以 放置皇后 
                vector<vector<int>> temp_mark = mark; // 备份 mark
                item[idx][i] = 'Q';
                put_down_the_queen(idx,i,mark);
    
                // 递归链条 
                generate(idx+1,n,item,res,mark); // 递归下一行 皇后
    
                // 回溯
                mark = temp_mark;
                item[idx][i] = '.';
            }
        }
    
    }
    
    vector<vector<string>> solveNQueens(int n){
        vector<vector<string>>res; // 最终的结果 
        vector<vector<int>> mark; // 标记棋盘的 二维数组 
    
        vector<string> item; // 存储 某个结果 
    
        // 初始化 mark 和 item
        for(int i=0;i<n;i++){
            mark.push_back(vector<int>());
            for(int j=0;j<n;j++){
                mark[i].push_back(0); // 初始 mark
            }
            // 初始化 item 
            item.push_back("");
            item[i].append(n,'.'); // item[0] = n个 点 
        }
    
        generate(0,n,item,res,mark);
    
        return res;
    }
    void myPrint(vector<vector<string>>& ret){
        for(int i=0;i<(int)ret.size();i++){
            for(int j=0;j<(int)ret[i].size();j++){
                cout <<ret[i][j]<<endl;;
            }
            cout << "=========" <<  endl;
        }
    }
    
    int main(){
        vector<vector<string>> ret = solveNQueens(4);
    
        myPrint(ret);
    
        return 0;
    }
    
    /*
    .Q..
    ...Q
    Q...
    ..Q.
    =========
    ..Q.
    Q...
    ...Q
    .Q..
    =========
    */
    View Code

    预备知识:分治算法与归并排序

    代码实现:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void mergeTwoSortedVec(vector<int>& vec1,vector<int>& vec2,vector<int>& res ){
    
        int i = 0;
        int j = 0;
        int size1 = vec1.size();
        int size2 = vec2.size();
        while(i<size1 && j<size2){
            if(vec1[i] <= vec2[j]){ // 相等的话,放到前一个数组
                res.push_back(vec1[i]);
                i++;
            }else{
                res.push_back(vec2[j]);
                j++;
            }
        }
        // 将 vec1 和 vec2 剩余的元素 push 进 res
        for(;i<size1;i++){
            res.push_back(vec1[i]);
        }
        
        for(;j<size2;j++){
            res.push_back(vec2[j]);
        }
    }
    
    
    
    
    
    
    void myPrint(vector<int> vec){
        for(auto it = vec.cbegin();it != vec.cend();it++){
            cout <<*it << " ";
        }
        cout << endl;
    }
    
    int main(){
    
        vector<int> vec1 = {2,5,8,20};
        vector<int> vec2 = {1,3,5,7,30,50};
        vector<int> res;
        myPrint(vec1);
        myPrint(vec2);
        mergeTwoSortedVec(vec1,vec2,res);
    
        myPrint(res);
    
    
        return 0;
    }
    对两个有序数组进行归并排序

    分治算法 排序

    分治算法的时间复杂度:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void mergeTwoSortedVec(vector<int>& vec1,vector<int>& vec2,vector<int>& res ){
    
        int i = 0;
        int j = 0;
        int size1 = vec1.size();
        int size2 = vec2.size();
        while(i<size1 && j<size2){
            if(vec1[i] < vec2[j]){ 
                res.push_back(vec1[i]);
                i++;
            }else{
                res.push_back(vec2[j]);
                j++;
            }
        }
        // 将 vec1 和 vec2 剩余的元素 push 进 res
        for(;i<size1;i++){
            res.push_back(vec1[i]);
        }
        
        for(;j<size2;j++){
            res.push_back(vec2[j]);
        }
    }
    
    void mergeSort(vector<int>& vec){
        // base case 
        int size = vec.size();
        if(size <= 1){ // 如果问题足够小 直接求解
            return;
        }
        int mid =  vec.size()/2; 
        vector<int> sub_vec1; // 将原问题拆分为 两个 规模相同的问题
        vector<int> sub_vec2;
        for(int i=0;i<mid;i++){
            sub_vec1.push_back(vec[i]);
        }
        for(int i=mid;i<size;i++){
            sub_vec2.push_back(vec[i]);
        }
        // 递归链条 
        mergeSort(sub_vec1);
        mergeSort(sub_vec2);
    
        vec.clear();
        mergeTwoSortedVec(sub_vec1,sub_vec2,vec); // 合并 
    }
    
    void myPrint(vector<int> vec){
        for(auto it = vec.cbegin();it != vec.cend();it++){
            cout <<*it << " ";
        }
        cout << endl;
    }
    
    int main(){
    
        vector<int> vec = {5,-7,9,1,1};
        myPrint(vec);
        mergeSort(vec);
        myPrint(vec);
    
    
    
        return 0;
    }
    使用分治对一个非有序数组进行排序

    例4:逆序数(LeetCode No.315)

    给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

    输入:nums = [5,2,6,1]
    输出:[2,1,1,0]
    解释:
    5 的右侧有 2 个更小的元素 (2 和 1)
    2 的右侧仅有 1 个更小的元素 (1)
    6 的右侧有 1 个更小的元素 (1)
    1 的右侧有 0 个更小的元素

    思路及代码

    使用分治来解决,

    思考:

    算法思路:

    插入j对应的元素时,就是直接j 对应的值,

    count 的顺序问题:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void mergeTwoSortedVec(vector<pair<int,int>>& vec1,vector<pair<int,int>>& vec2,vector<pair<int,int>>& res,vector<int>& count ){
    
        int i = 0;
        int j = 0;
        int size1 = vec1.size();
        int size2 = vec2.size();
        while(i<size1 && j<size2){
            if(vec1[i].first <= vec2[j].first){ 
                count[vec1[i].second] += j;
                res.push_back(vec1[i]);
                i++;
            }else{
                res.push_back(vec2[j]);
                j++;
            }
        }
        // 将 vec1 和 vec2 剩余的元素 push 进 res
        for(;i<size1;i++){
            count[vec1[i].second] += j;
            res.push_back(vec1[i]);
        }
        
        for(;j<size2;j++){
            res.push_back(vec2[j]);
        }
    }
    
    void mergeSort(vector<pair<int,int>>& vec,vector<int>& count){
        // base case 
        int size = vec.size();
        if(size <= 1){ // 如果问题足够小 直接求解
            return;
        }
        int mid =  vec.size()/2; 
        vector<pair<int,int>> sub_vec1; // 将原问题拆分为 两个 规模相同的问题
        vector<pair<int,int>> sub_vec2;
        for(int i=0;i<mid;i++){
            sub_vec1.push_back(vec[i]);
        }
        for(int i=mid;i<size;i++){
            sub_vec2.push_back(vec[i]);
        }
        // 递归链条 
        mergeSort(sub_vec1,count);
        mergeSort(sub_vec2,count);
    
        vec.clear();
        mergeTwoSortedVec(sub_vec1,sub_vec2,vec,count); // 合并 
    }
    
    void myPrint(vector<int> vec){
        for(auto it = vec.cbegin();it != vec.cend();it++){
            cout <<*it << " ";
        }
        cout << endl;
    }
    
    vector<int> countSmaller(vector<int>& nums) {
        vector<pair<int,int>> vec; // 将 nums[i] 和 i 绑定到一起 放入vec
        vector<int> count;
        for(int i=0;i<(int)nums.size();i++){
            vec.push_back(make_pair(nums[i],i));
            count.push_back(0); // 初始为0  
        }
        mergeSort(vec,count); // 使用vec中pair 的第一个数进行排序 
        return count;
    }
    
    int main(){
    
        vector<int> data = {5,-7,9,1,1};
        countSmaller(data);
    
    
        return 0;
    }
    View Code
    class Solution {
    private:
    void mergeSort(vector<pair<int,int>>& vec,vector<int>& count){
        // base case 
        int size = vec.size();
        if(size <= 1){ // 如果问题足够小 直接求解
            return;
        }
        int mid =  vec.size()/2; 
        vector<pair<int,int>> sub_vec1; // 将原问题拆分为 两个 规模相同的问题
        vector<pair<int,int>> sub_vec2;
        for(int i=0;i<mid;i++){
            sub_vec1.push_back(vec[i]);
        }
        for(int i=mid;i<size;i++){
            sub_vec2.push_back(vec[i]);
        }
        // 递归链条 
        mergeSort(sub_vec1,count);
        mergeSort(sub_vec2,count);
    
        vec.clear();
        mergeTwoSortedVec(sub_vec1,sub_vec2,vec,count); // 合并 
    }
    
    void mergeTwoSortedVec(vector<pair<int,int>>& vec1,vector<pair<int,int>>& vec2,vector<pair<int,int>>& res,vector<int>& count ){
    
        int i = 0;
        int j = 0;
        int size1 = vec1.size();
        int size2 = vec2.size();
        while(i<size1 && j<size2){
            if(vec1[i].first <= vec2[j].first){ 
                count[vec1[i].second] += j;
                res.push_back(vec1[i]);
                i++;
            }else{
                res.push_back(vec2[j]);
                j++;
            }
        }
        // 将 vec1 和 vec2 剩余的元素 push 进 res
        for(;i<size1;i++){
            count[vec1[i].second] += j;
            res.push_back(vec1[i]);
        }
        
        for(;j<size2;j++){
            res.push_back(vec2[j]);
        }
    }
    
    
    
    public:
    vector<int> countSmaller(vector<int>& nums) {
        vector<pair<int,int>> vec; // 将 nums[i] 和 i 绑定到一起 放入vec
        vector<int> count;
        for(int i=0;i<(int)nums.size();i++){
            vec.push_back(make_pair(nums[i],i));
            count.push_back(0); // 初始为0  
        }
        mergeSort(vec,count); // 使用vec中pair 的第一个数进行排序 
        return count;
    }
    
    
    
    
    
    
    
    
    
    
    
    };
    View Code
  • 相关阅读:
    IconRes提供免费高质量的Material风格android官方图标库
    android中的所谓观察者模式
    Android总结篇——Intent机制详解及示例总结
    SpringMVC注解@initbinder解决类型转换问题
    ubuntu16.04上安装tomcat7
    ImportError: No module named corsheaders
    linux 网卡
    工控机安装Ubuntu14.04
    python2安装django
    Ubuntu14.04 terminal添加右键
  • 原文地址:https://www.cnblogs.com/zach0812/p/13656569.html
Copyright © 2011-2022 走看看