357. Count Numbers with Unique Digits

leetcode-23-DynamicProgramming-1

解题思路:

用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

leetcode-23-DynamicProgramming-1

解题思路:

这道题使用一个数组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

leetcode-23-DynamicProgramming-1

解题思路:

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

leetcode-23-DynamicProgramming-1

解题思路:

这道题类似于求最长递增子序列。。考虑的是,大的数整除小的数,所以现将数组排序。然后用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

leetcode-23-DynamicProgramming-1

解题思路:

可以将所有数字分为两个组,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

leetcode-23-DynamicProgramming-1

解题思路:

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

  

 

 

相关文章:

  • 2022-01-13
  • 2021-08-12
  • 2021-12-15
  • 2021-06-11
  • 2021-08-15
  • 2021-10-30
  • 2021-09-06
猜你喜欢
  • 2021-08-11
  • 2021-07-22
  • 2022-02-09
  • 2021-11-15
  • 2021-07-12
  • 2021-08-13
  • 2021-08-25
相关资源
相似解决方案