代码随想录算法训练营day49|121.买卖股票的最佳时机122.买卖股票的最佳时机II剑指Offer18.删除链表的节点22.链表中倒数第k个节点25.合并两个排序链表52.两个链表的第一个公共节点

121.买卖股票的最佳时机

题目链接

开始纠结为什么持有股票的递推公式也要取max,不应该取最小的吗,后来发现,因为卡哥是直接取了负号,那自然原本越小的正数加了负号就会变得更大。

本题最后一定是不持有股票比持有股票的金额要多,因为前面持有股票是一个负数,卖出后加一个正数,一定会更大。

本题每一天有两种状态,持有和不持有。

因为只能买卖一次,所以买之前手头上的钱一定是0。

class Solution {
public:
    int maxProfit(vector& prices) {
        vector> dp(prices.size(),vector(2));
        dp[0][0]=-prices[0];//正常的顺也肯定是先持有再不持有
        dp[0][1]=0;
        for(int i=1;i

122.买卖股票的最佳时机II 

题目链接

本题和上一题唯一的区别在于,买之前手头上的现金不一定是0了,可能是买卖多次所收获的利润,所以递推公式为dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i])。

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

剑指Offer18.删除链表的节点

题目链接

这题简单多了,因为题目中说了,保证链表中节点的值互不相同,并且不需要free或者delete被删除的节点。

首先在原链表直接删除。

class Solution {
public:
    ListNode* deleteNode(ListNode* head, int val) {
        if(head!=NULL&&head->val==val){
            head=head->next;
        }
        ListNode* cur=head;//必须从head开始,因为我们要删除的是cur->next
        while(cur!=NULL&&cur->next!=NULL){
            if(cur->next->val==val){
                cur->next=cur->next->next;
            }
            else{
                cur=cur->next;
            }
        }
        return head;
    }
};

我们可以设一个虚拟头结点,统一删除操作。

class Solution {
public:
    ListNode* deleteNode(ListNode* head, int val) {
        ListNode* dummyhead=new ListNode(0);
        dummyhead->next=head;//错因,这句话没有写
        ListNode* cur=dummyhead;
        while(cur->next){//因为我们删除的是cur->next,所以只要cur->next不为空就好了
            if(cur->next->val==val){
                cur->next=cur->next->next;
            }else{
                cur=cur->next;
            }
        }
        return dummyhead->next;
    }
};

错因:设了虚拟头结点之后没有和原链表连起来。

22.链表中倒数第k个节点

题目链接

思路:双指针。一个快指针先走k-1步,然后同时移动快慢指针,最后返回满指针即可。

class Solution {
public:
    ListNode* getKthFromEnd(ListNode* head, int k) {
        ListNode* slow=head;
        ListNode* fast=head;
        k--;
        while(k--){
            fast=fast->next;
        }
        while(fast->next){
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
    }
};

slow和fast要分开定义,这个还是不太懂。

25.合并两个排序的链表

题目链接

思路:归并排序,新设置一个dummy节点,方便后续操作。本题相当于操作三个链表,自然要优三个指针进行处理,l1,l2就直接移动头指针即可(反正最后要返回的是合并后的新链表),新链表用cur指针进行遍历。

该题的图解思路参考B站视频​​​​​​​

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* dummy=new ListNode(0);//实例化
        ListNode* cur=dummy;
        while(l1&&l2){
            if(l1->val<=l2->val){
                cur->next=l1;//开始实例化了一个dummy节点,所以不用担心cur为空,不会报空指针异常的错误
                l1=l1->next;//移动l1指针,反正最后返回的是dummy->next,改变l1,l2无所谓
            }else{
                cur->next=l2;
                l2=l2->next;
            }
            cur=cur->next;
        }
        cur->next=(l1==NULL)?l2:l1;
        return dummy->next;
    }
};

52.两个链表的第一个公共节点

题目链接

思路:第一种思路是分别计算两个链表的长度,假设差值是a-b,然后让长的链表先多走a-b步,再同时走就能找到公共节点,就不写代码了。

第二种是两个同时走如果第一轮(恰好公共节点之前两个链表的长度相同)没有找到的话,就让A指针指回headB,B指针指回headA,然后再同时走即可,当然不相交的话,也可能A和B同时走到NULL,那最后返回A或B就是NULL,也没问题。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA==NULL||headB==NULL) return NULL;
        ListNode* A=headA;
        ListNode* B=headB;//新设两个指针,因为如果第一轮没找到公共节点,还要指回去
        while(A!=B){
            A=(A==NULL)?headB:A->next;
            B=(B==NULL)?headA:B->next;
        }
        return A;
    }
};

注意开始要判断一下,只要有一个为空的话直接返回NULL。

注意三目运算符的使用。

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