代码随想录算法训练营day50|123.买卖股票的最佳时机III188.买卖股票的最佳时机IV 剑指offer21、57、58-I、12、面试题13

123.买卖股票的最佳时机III

题目链接

思路:本题中第i天有五种状态:不操作、第一次持有、第一次不持有、第二次持有、第二次不持有。

注意可以同一天进行买卖,而且是多次买卖。

class Solution {
public:
    int maxProfit(vector& prices) {
        int len=prices.size();
        vector> dp(len,vector(5));
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        dp[0][2]=0;
        dp[0][3]=-prices[0];
        dp[0][4]=0;
        for(int i=1;i

188.买卖股票的最佳时机IV

题目链接

本题和上一题不同的就是,第i天可以有2*k+1种状态,需要额外用一个变量j记录第i天第j次买卖。

至于边界条件,可以代入k=2,进行验证。

class Solution {
public:
    int maxProfit(int k, vector& prices) {
        int len=prices.size();
        if(len==0) return 0;
        vector> dp(len,vector(2*k+1,0));
        for(int i=1;i<2*k;i+=2){
            dp[0][i]=-prices[0];//第0天持有一定是买入//错因:是prices[0],不是prices[i]
        }
        for(int i=1;i

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

题目链接

思路:快排的思路。只要left和right不指向同一个元素,如果left指向的元素一直是奇数,就一直往后移动left指针,如果right指向的元素一直是偶数,就一直往前移动right指针,然后两个指针停止的位置肯定是left指向偶数,right指向奇数,那么将这两个元素进行交换即可,然后再开始下一轮。

class Solution {
public:
    vector exchange(vector& nums) {
        int left=0,right=nums.size()-1;
        while(left

剑指 Offer 57. 和为s的两个数字

题目链接

思路:一说是在排序数组中查找元素,自然就是二分查找。

class Solution {
public:
    vector twoSum(vector& nums, int target) {
        for(int i=0;i{nums[i],fin};
                else if(nums[mid]{};
    }
};

剑指 Offer 58 - I. 翻转单词顺序

题目链接

思路:双指针法,快指针用于获取我们想要的元素,满指针指向我们获取的新元素更新在哪里。先去除字符串中多余的空格,然后整体反转+局部反转。其实相当于同时操作新数组和旧数组,外层循环是快指针用于遍历旧数组,然后用满指针更新新数组。

class Solution {
public:
    void reverse(string&s,int start,int end){
        for(int i=start,j=end;i

错因:1、更新完新数组之后忘记改字符串的大小了,因为我们是在原数组上直接进行更新的,所以要改变新数组的大小。

2、在反转单词的时候for循环的边界条件写错了,应该有等于,因为此时for循环里的下标i是为了我们记录单词的末尾位置,但是小标i指向的是单词的末尾位置的后一个位置,所以要有等于s.size()。

剑指 Offer 12. 矩阵中的路径

题目链接

思路:回溯法。注意同一个格子的元素不能重复访问,所以将它改成一个#(因为boardword仅由大小写英文字母组成,所以#一定不会被访问),然后回溯的时候再改回去即可。当然也可以用visited数组记录访问情况,但是这样的空间复杂度比较高。

class Solution {
public:
    bool dfs(vector>& board, string word,int k,int i,int j){
        int m=board.size();
        int n=board[0].size();
        if(!(i>=0&&i=0&&j>& board, string word) {
        for(int i=0;i

错因:dfs的递归终止条件中的边界条件写错,写成了i<=m和j<=n,应该是<。

本题因为单词内字符是有顺序的,所以可能前面的字符不符合,但是后面的字符符合了,所以必须要进行回溯。

面试题13. 机器人的运动范围

题目链接

本题和上一题不一样的是,如果遍历到一个格子是不符合条件的,那它一定就是不符合了,所以不用进行回溯。

class Solution {
public:
    int getval(int i,int j){//直接求出两个数的数位之和
        int res=0;
        while(i){
            res+=i%10;
            i/=10;
        }
        while(j){
            res+=j%10;
            j/=10;
        }
        return res;
    }
    int dfs(int i, int j, int k,int m,int n,vector>& visited){
        if(i>=m||j>=n||getval(i,j)>k||visited[i][j]==true) return 0;//visited[i][j]==true说明该点已经被之前某条路径访问过了,已经计算过了,如果再沿着这个位置往右往下走的话,必然会走重复的路径//就相当于设了个障碍,不能再继续往后搜索了,该点也不能计算,所以返回0
        visited[i][j]=true;
        return 1+dfs(i+1,j,k,m,n,visited)+dfs(i,j+1,k,m,n,visited);
    }
    int movingCount(int m, int n, int k) {
        vector> visited(m,vector(n,false));
        return dfs(0,0,k,m,n,visited);
    }
};

注意数位求和的过程。

开始很纠结为什么dfs函数里,visited[i][j]==true,要返回0。因为visited[i][j]==true说明该点已经被之前某条路径经过了,也就是已经计算过了,如果是true就返回0,也就是当前路径经过该点的后面的路径不要再进行搜索了,而且该点也不能进行计算,所以直接返回0。

本题用unordered_set的写法还是不太会,有待继续研究。

你可能感兴趣的:(算法,leetcode,动态规划)