Leetcode 力扣动态规划笔记 部分简单题算法总结CPP

53. Maximum subarray
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

在一个整数数组里找到和最大的部分数组并返回和。

简单题。这道题不完全算动态规划,可以用“滑窗法”解决。思路:如果数组里面全为负数,那么第一个数就是最大值,如果数组里面全为正数,那么整个数组的和最大。如果数组里面有正有负,那么加上数组里的下一个数,有可能让已经得到的和变大或变小,我们可以想象一个“滑窗”,这个“滑窗”最开始只有数组里的第一个数,然后滑窗左端不变,右边向右移动,如果下一个数让滑窗里的总和变小了,那么保留变小之前的这个值,叫它running_sum。但滑窗左端不变,右边继续移动,每次总和变小都比较一下running_sum,只保留最大值。如果下一个数让滑窗里的总和小于0,滑窗左端移动到下下个数,重新开始。最后返回running_sum中的最大值。时间O(n)。

#include<vector>
using namespace std;

class Solution
{
    
public:
    int maxSubArray(vector<int>& nums)  {
        int running_sum=0;
        int max;
        int i,j;
        int n=nums.size();
        
        if(n==0) return INT_MIN;
        max=nums[0];
        
        for(i=0;i<n && nums[i]<=0;i++)  {
            if(nums[i]>max)
            max=nums[i];
        }
        
        for(;i<n;i++)  {
            running_sum+=nums[i];
            if(running_sum<0)running_sum=0;
            if(nums[i]>=0 && ((i==n-1) || nums[i+1]<0))if(running_sum>max)max=running_sum;    
        }
        return max;  
    }         
};

70. Climbing Stairs
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.

爬一个有n层的楼梯,每次 可选择上一层或上两层,有多少种爬法?

DP简单题。先找递归公式:假设爬到第n层有f(n)种爬法,发现其实n只取决于f(n-1)和f(n-2):可以从下面一层或下面两层直接上来:f(n)=f(n-1)+f(n-2),类似斐波那契数列。使用一个数组table[n]自下而上记录上到每层的爬法:

class Solution {
public:
    int climbStairs(int n) {   
    
        vector<int> steps(n+1,0);    
        if(n<3)return n;
        steps[1]=1;
        steps[2]=2;
        for(int i=3;i<=n;i++)
            steps[i]=steps[i-1]+steps[i-2];   
        return steps[n];
    }
};

时间o(n)。

121. Best Time to Buy and Sell Stock
Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.
Note that you cannot sell a stock before you buy one.

买卖股票问题:数列price[i]里的元素i是每天股票的价格,选择最合适的时间买入和卖出(先买入后卖出)以得到最大利益。

简单题。类似滑窗法。思路:如果存在prices[high]-prices[low]利益最大,那么prices[low]一定是high之前的最低点,prices[high]一定是low之后的最高点。需要两个变量:一保存当前最大利益,二保存已检查过的数组部分的最小值。时间O(n)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        
        if(prices.size()==0) return 0;
        
        int max_pro=0;
        int min_cur=prices[0];
        int i;
        
        for(int i=0;i<prices.size();i++) {
            min_cur=min(min_cur, prices[i]);
            max_pro=max(max_pro, prices[i]-min_cur);            
        }
        
        return max_pro;
    }
};

198. House Robber
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

在一列数组nums里取一些不相邻的数,使得和最大。

DP解法很容易,假设到前i个值时能得到的最大和为c[i],如果nums[i]包含在内,那么nums[i-1]不包含在内,nums[i+1]也不能包含在内,c[i+1]=c[i]。反之nums[i+1]可以包含在内,c[i+1]=c[i]+nums[i+1]。我们只需要得到这个最大值,数组c都可以省略,看O(n)算法(用pp保存到前两位的最大值,用p保存到前一位的最大值,cur保存当前最大值):

class Solution {
public:
    int rob(vector<int>& nums) {
        int p = 0, pp = 0, cur = 0;
        
        for (auto n : nums) {
            cur = max(p, pp + n);
            pp = p, p = cur;
        }
        
        return cur;
    }
};

392. Is Subsequence
Given a string s and a string t, check if s is subsequence of t.
You may assume that there is only lower case English letters in both s and t. t is potentially a very long (length ~= 500,000) string, and s is a short string (<=100).
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, “ace” is a subsequence of “abcde” while “aec” is not).

检查字符串s是否字符串t的子序列。子序列详解可查看算法与数据结构学习笔记-字符串之最长公共子序列,LCS问题的动态规划解法。 直接上代码,时间O(t的长度)。

class Solution {
public:
    bool isSubsequence(string s, string t) {
        
        if(s.length()==0)return true;
        if(t.length()==0)return false;
        
        int k=0;
        
        for(int i=0;i<t.length();i++) {
            if(t[i]==s[k])k++;
            if(k==s.length())return true;
        }
        return false;
    }
};

746. Min Cost Climbing Stairs
On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed).
Once you pay the cost, you can either climb one or two steps. You need to find minimum cost to reach the top of the floor, and you can either start from the step with index 0, or the step with index 1.

在一个楼梯上,每一级台阶i都有一个非负的“价格”。价格保存在数组cost[i]中。按照价格付费以后可以选择上一级和上两级。找到上到顶端的最小费用,i从0开始。
DP简单题。注意给的数组cost里最后一个值并不是顶端,到达数组末端以后还需要再付费才能到顶。假设有n级台阶,最后的结果要么是到达数组末端,付cost[n-1]的费用,要么到达数组末端前一个,付cost[n-2]的费用并上两级台阶。
先找到递归公式:如果到达第i层台阶的费用最低,那么这个最低值要么是到达第i-1层的最低费用加cost[i-1],要么是到达第i-2层的最低费用加上cost[i-2]。递归公式:f(n)=min(f(i-1)+cost(i-1),f(i-2)+cost(i-2)。可以用一个数组c保存所有的f(i)值。

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        
        vector<int> c(cost.size()+1,0);
        
        for(int i=2;i<=cost.size();i++)
            c[i]=min(c[i-1]+cost[i-1],c[i-2]+cost[i-2]);
        
        return c[cost.size()];
    }
};

1025. Divisor Game
Alice and Bob take turns playing a game, with Alice starting first.
Initially, there is a number N on the chalkboard. On each player’s turn, that player makes a move consisting of:
Choosing any x with 0 < x < N and N % x == 0.
Replacing the number N on the chalkboard with N - x.
Also, if a player cannot make a move, they lose the game.
Return True if and only if Alice wins the game, assuming both players play optimally.

最开始,黑板上有一个数字N。Alice和Bob要玩一个游戏:Alice先走,每次轮到一个选手,这个选后可以选择一个小于N的整整数x,使得N % x == 0,然后把黑板上的N换成N-x。如果轮到某个选手,这个选手找不出合适的x,就输了。
如果Alice可以赢,返回true,否则返回false,每个选手都会尽力争取胜利。
这是DP简单题里比较难想的一道了。如果一个选手选择了x,而N-x是质数,那么对手就找不到合适的x,能够获得胜利。
可以先找一些数字试试看,如果获得了数字8,那么可以选1,得到7,对手输。得到4,选1,对手得到3,对手输。得到15,可以选1,3,5,分别让对手获得14,12,10,那么对手选1,1,5,对手胜利。如果N是质奇数,毫无疑问Alice输。如果N是奇数但不是质数,Alice选择的x必定是奇数,那么对手获得一个偶数。如果N是偶数(包括2),那么走如下路线:

Alice选奇数x,对手得到奇数
对手只能选奇数x,Alice得到偶数

Alice选偶数x,对手得到偶数
对手可能选奇数x,Alice可能得到奇数。

Alice想赢的话,遇到偶数就选奇数x,丢给对方一个奇数,如果这个奇数是质数,那么Alice就赢了。如果这个奇数不是质数,对方只能再丢回来一个偶数,Alice可以一直按照这种方式下去获得胜利,所以N是大于2的偶数的话,Alice有必胜策略。如果N是奇数,Alice要么直接输掉要么丢给对手一个偶数,对手可以用这个策略必胜。
所以N不是质数时,偶数必胜,奇数必败。这是一道数学题。O(1)。

class Solution {
public:
    bool divisorGame(int N) {
       
    return N%2==0;     
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值