zoukankan      html  css  js  c++  java
  • leetcode-23-DynamicProgramming-1

    357. Count Numbers with Unique Digits

    解题思路:

    用arr[i]存放长度为i时,各位互不相同的数字的个数,所以arr[1]=10,arr[2]=9*9。(第一位要为1,第二位与第一位要不同)

    arr[3] = arr[2]*8,所以arr[i]=arr[i-1]*(10 - (k-1))。之后求和就可以了。

    int countNumbersWithUniqueDigits(int n) {
            if (!n)
                return 1;
            if (n == 1)
                return 10;
            if (n == 2)
                return 91;
            int sum = 0;
            int arr[n + 2];
            arr[1] = 10;
            arr[2] = 81;
            for (int i = 3; i <= n; i++)
                arr[i] = arr[i-1] * (11 - i);
            for (int i = 1; i <= n; i++) {
                sum += arr[i];
            }
            return sum;
        }
    

      


    5. Longest Palindromic Substring

    解题思路:

    这道题使用一个数组dp[i][j]存储子串s[i...j]是否为回文串。那么dp[i][i]=true(i = 0...n), dp[i][i-1]=true(i = 1...n)

    其他为false。判断的时候,dp[i][j] = (s[i] == s[j] && dp[i+1][j-1] == true)。同时,需要记录最长回文串的位置。

    枚举子串时,从k=2开始到n。

    string longestPalindrome(string s) {
            if (s.length() < 2)
                return s;
            int left = 0;
            int right = 0;
            bool dp[s.length()][s.length()];
            memset(dp, false, sizeof(dp));
            dp[0][0] = true;
            for (int i = 1; i < s.length(); i++) {
                dp[i][i] = true;
                dp[i][i-1] = true;
            }
            int i, j, k;
            for (k = 2; k <= s.length(); k++) {
                for (i = 0; i <= s.length() - k; i++) {
                    j = i - 1 + k;
                    if (s[i] == s[j] && dp[i+1][j-1] == true) {
                        dp[i][j] = true;
                        if (right - left + 1 < k) {
                            left = i;
                            right = j;
                        }
                    }
                }
            }
            return s.substr(left, right - left + 1);
        }
    

      


    516. Longest Palindromic Subsequence

    解题思路:

    subsequence与substring的区别在于它可以是不连续的,此处的思路是:

    用dp[i][j]存储子序列s[i...j]中最长回文串的长度。初始化时,除了dp[i][i]=1外,其它都置为0。

    枚举子序列的长度,从2开始。所以如果s[i]==s[j],那么dp[i][j] = dp[i+1][j-1]+2;否则

    dp[i][j] = max(dp[i-1][j], dp[i][j-1])。最后只要返回dp[0][n-1]就可以了。

    int longestPalindromeSubseq(string s) {
            if (s.size() < 2)
                return s.size();
            int dp[s.size()][s.size()];
            for (int i = 0; i < s.size(); i++) {
                for (int j = 0; j < s.size(); j++) {
                    dp[i][j] = 0;
                }
                dp[i][i] = 1;
            }
            int i, j, k;
            for (k = 1; k < s.size(); k++) {
                for (i = 0; i < s.size() - k; i++) {
                    j = i + k;
                    if (s[i] == s[j])
                        dp[i][j] = dp[i+1][j-1] + 2;
                    else
                        dp[i][j] = dp[i+1][j] > dp[i][j-1] ? dp[i+1][j] : dp[i][j-1];
                }
            }
            return dp[0][s.size()-1];
        }
    

      


     368. Largest Divisible Subset

    解题思路:

    这道题类似于求最长递增子序列。。考虑的是,大的数整除小的数,所以现将数组排序。然后用dp[i]记录以第i个数结尾的最长可整除子集的长度。

    那么状态转移方程为:dp[i] = max{dp[j] + 1},j = 0...i-1。同时,要求dp[j]%dp[i]==0。另外,因为需要记录子集的内容,所以使用另一个

    数组set来保留加入的序号(针对nums的),使用max记录最大长度,last记录最后一个序号。

    需要注意的是,C++中数组的赋值,不能用int dp[n] = {1},因为这样只将dp[0]赋值为1,其他为0;也不能用memset,很奇怪==

    vector<int> largestDivisibleSubset(vector<int>& nums) {
            if (nums.size() < 2)
                return nums;
            // sort
            sort(nums.begin(), nums.end());
            // this way, only get 1,0,0
            //int dp[nums.size()] = {1};
            int dp[nums.size()];
            // wrong!
            //memset(dp, 1, nums.size());
            int set[nums.size()];
            for (int i = 0; i < nums.size(); i++) {
                dp[i] = 1;
                set[i] = -1;
            }
            int max = 0;
            int last = -1;
            vector<int> result;
            for (int i = 1; i < nums.size(); i++) {
                for (int j = 0; j < i; j++) {
                    if (nums[i] % nums[j] == 0 && dp[j] + 1 > dp[i]) {
                        dp[i] = dp[j] + 1;
                        set[i] = j;
                    }
                    if (dp[i] > max) {
                        max = dp[i];
                        last = i;
                    }
                }
            }
            // get result
            for (int i = last; i >= 0;) {
                result.insert(result.begin(), nums[i]);
                i = set[i];
            }
            return result;
        }
    

      


    494. Target Sum

    解题思路:

    可以将所有数字分为两个组,positive和negative,那么

    positive - negative = target

    positive + negative = sum

    所以两式相加,2postive = target + sum。所以可以把所有数字变为原来的两倍,选其中一部分数字作为positive,剩下的自然是negative,

    看有多少种选法可以使得总和为target+sum。因此使用数组dp[i]来记录总和达到i的方法数。注意:

    1) 初始化dp[0] = 1

    2) 只考虑j>=nums[i]的情况,而且j要从target开始,不能从0开始,否则会WA

    int findTargetSumWays(vector<int>& nums, int S) {
            int sum = 0;
            for(int i = 0; i < nums.size(); i++) {
                sum += nums[i];
                nums[i] *= 2;
            }
            if (sum < S)
                return 0;
            int target = sum + S;
            int dp[target + 1];
    // initialize
            dp[0] = 1;
            for (int i = 0; i < nums.size(); i++) {
    // ATTENTION: j
                for (int j = target; j >= 0; j--) {
                    if (j >= nums[i]) {
                        dp[j] += dp[j - nums[i]];
                    }
                }
            }
            return dp[target];
        }
    

      


    343. Integer Break

    解题思路:

    首先n=2时返回1,n=3时返回2,这两个需要特别考虑。然后用result[i]存储和为i时乘积最大值,因此

    result[i]=max{result[i-3]*3, result[i-2]*2}。而关于result[2]和result[3]的值,需要观察。。

    i = 4, max(1*3, 2*2) = 4

    i = 5, max(result[2]*3, result[3]*2) = max(2*3, 3*2) = 6

    i = 6, max(result[3]*3, result[4]*2) = max(3*3, 4*2) = 9

    因此,result[2] = 2, result[3] = 3

    int integerBreak(int n) {
            int result[n+1] = {0};
            if (n <= 3)
                return n-1;
            result[2] = 2;
            result[3] = 3;
            for (int i = 4; i <= n; i++) {
                result[i] = 3 * result[i-3] > 2 * result[i-2] ? 3 * result[i-3] : 2 * result[i-2];
            }
            return result[n];
        }
    

     


    486. Predict the Winner

    https://leetcode.com/problems/predict-the-winner/#/description

    简单的说就是两个人轮流抽牌,每个人都可以从头抽或者从尾抽,抽到了就加相应的分数,最后看谁的分高。

    解题思路:

    用了递归。。

    bool PredictTheWinner(vector<int>& nums) {
            return myFunc(nums, 0, nums.size()-1) >= 0;
        }
        int myFunc(vector<int>& nums, int start, int end) {
            if (start == end)
                return nums[start];
            int i = nums[start] - myFunc(nums, start+1, end);
            int j = nums[end] - myFunc(nums, start, end-1);
            return i > j ? i : j;
        }
    

      

     

  • 相关阅读:
    企业应用开发中最常用c++库
    ESOURCE_LOCKED
    c++标准之于gcc/vc/boost等实现相当于jsr规范之于sunjdk/ibmjdk/tomcat/weblogic等实现
    c++的各种类型转换方式
    c++的友元类、方法及其益处
    c/c++的typedef/using类型别名
    c++的class声明及相比java的更合理之处
    c++ sleep(windows/linux)
    c++不自动生成相关函数比如赋值、拷贝函数
    c++继承、多态以及与java的行为差异之处
  • 原文地址:https://www.cnblogs.com/pxy7896/p/6769600.html
Copyright © 2011-2022 走看看