• (动态规划、递归) leetcode 87. Scramble String


    思路:用递归来做感觉比动态规划简单,题目让我们判断s1和s2是否是scramble string,则s1上(从左起计数)有一个长度为 i 的分割点将s1分为s1_l 和 s1_r 两段 分别与 s2的(从左起计数一个长度为i的) s2_l 和 s2_r 互为 scramble string;或者与 s2的(从右起计数一个长度为i的)s2.substr(s-i) 和 s2.substr(0, s-i) 互为 scramble string 。

    1)C++ 中的 substr(pos, len) 表示从 索引为pos开始的子字符串,截取长度为len的子串,即子串的索引为[pos, pos+len) 注意是左闭右开区间; substr(pos) 表示从索引pos开始到字符串末尾的子字符串,即 [pos, size ) size为字符串长度,注意是左闭右开区间。

    2)sort() 可以按字典序排列 string 类型的字符串。

    3)== 可以用来判断两个字符串是否相同。

    class Solution {
    public:
        bool isScramble(string s1, string s2) {
            int s = s2.size(); 
            if(s1.size()!=s2.size())
                return false;
            if(s1==s2)
                return true;
            string str1 = s1, str2 = s2;
            sort(str1.begin(), str1.end());
            sort(str2.begin(), str2.end());
            if(str1 != str2)
                return false;
            for(int i=1; i<s1.size(); ++i){
                string st1_l = s1.substr(0, i), st1_r = s1.substr(i);
                string st2_l = s2.substr(0, i), st2_r = s2.substr(i);
                if((isScramble(st1_l, st2_l) && isScramble(st1_r, st2_r)) || ( isScramble(st1_l, s2.substr(s-i) ) && isScramble(st1_r, s2.substr(0, s-i) ) ))
                    return true;
            }
            return false;
            
        }
    };

    递归:注意 / 的意思是浮点数的除法,所以要先将int型的nums转化为 double 型的 arr;每次选两个索引位置不相同的元素,进行加减乘除操作,并将结果放入数组中,然后递归求解,直到数组最后只剩下一个元素,若这个元素值为24,则返回true。最后若两层遍历结束后都没有找到最后的结果为24,则返回false。

    class Solution {
    public:
        bool judgePoint24(vector<int>& nums) {
            vector<double> arr(nums.begin(), nums.end());
            
            return helper(arr);
        }
        
        bool helper(vector<double>& arr){
            int size = arr.size();
            if(size == 1 )
                return (abs(arr[0] - 24) < 1e-6);
            for(int i=0; i<size; ++i){
                for(int j=0; j<size; ++j){
                    if(i==j)
                        continue;  //不能取相同的元素
                    vector<double> new_arr;
                    for(int k=0; k<size; ++k)
                        if(k!=i && k!=j) new_arr.push_back(arr[k]);
                    new_arr.push_back(-1);
                    
                    double a = arr[i], b = arr[j];
                    
                    new_arr.back() = a+b;
                    if (helper(new_arr))
                        return true;
                    
                    new_arr.back() = a-b;
                    if (helper(new_arr))
                        return true;
                    
                    new_arr.back() = a*b;
                    if (helper(new_arr))
                        return true;
                    
                    new_arr.back() = a/b;
                    if (helper(new_arr))
                        return true;
    
                }
            }
            return false;
        }
    };

    感觉这道题的题意有点难理解啊!而且难哭了 :(

    1)青蛙初始在第一块石头上,假设一开始只能跳一个单位

     2)若青蛙前一步跳了k个单位,则它的下一步只能是k-1, k, k+1 个单位。且只能往前跳不能往后退。

    动态规划: 使用map,它的key 表示当前石头的位置pos,value 是一个包含 jumpsize的集合set,其中每个 jumpsize 代表可以通过大小为 jumpysize 大小的一跳到达当前位置。首先对map初始化,key 为所有石头的位置,除了位置 0 对应的 value 为包含一个值 0 的集合以外(dp[0] = 0 ),其余都初始化为空集。接下来,依次遍历每个位置上的石头。对于每个currentPosition,遍历 value 中每个 jumpsize,,对于每个 jumpsize,newjumpsize 分别为 jumpsize−1,jumpsize,jumpsize+1, 判断位置 currentPosition + newjumpsize 是否存在于 map 中。如果找到了,就在位置 currentPosition + newjumpsize 对应的 value 集合里新增 newjumpsize。重复这个过程直到结束。如果在结束的时候,最后一个位置对应的集合非空,那也就意味着我们可以到达终点,如果还是空集那就意味着不能到达终点。

    class Solution {
    public:
        bool canCross(vector<int>& stones) {
            unordered_map<int, unordered_set<int>> dp;
            for (auto position : stones)
                dp[position] = unordered_set<int>();
            dp[0].insert(0);
            for (auto position : stones) {
                for (auto k : dp[position]) {
                    // k - 1
                    if (k - 1 > 0 && dp.find(position + k - 1) != dp.end())
                        dp[position + k - 1].insert(k - 1);
                    // k
                    if (dp.find(position + k) != dp.end())
                        dp[position + k].insert(k);
                    // k + 1
                    if (dp.find(position + k + 1) != dp.end())
                        dp[position + k + 1].insert(k + 1);
                }
            }
            return !dp[stones.back()].empty();
        }
    };
  • 相关阅读:
    Makefile学习笔记1
    Shell脚本学习笔记8——跳出循环
    Shell脚本学习笔记7——case...esac
    Shell脚本学习笔记6——循环语句
    Linux命令学习笔记3:touch命令
    Linux命令学习笔记2:ll命令
    Linux命令学习笔记1:ln命令
    Shell脚本学习笔记5——if条件语句
    Shell 脚本学习笔记4——Shell脚本中 '$' 符号的多种用法
    利用C++创建DLL并C#调用
  • 原文地址:https://www.cnblogs.com/Bella2017/p/11217098.html
Copyright © 2020-2023  润新知