考研算法笔记(自用)

文章详细介绍了LeetCode中的几个经典算法问题,包括买卖股票最佳时机、二叉树的中序遍历、删除链表倒数第n个节点的两种方法、交换链表对以及旋转链表。同时,文章提到了解决这些问题的关键技巧,如动态规划、双指针和链表操作,并强调了边界条件的处理和优化策略。
摘要由CSDN通过智能技术生成

+++++++++++++++++++

考研算法笔记(自用)

leetcode121:买卖股票的最佳时机:

描述:

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

答案

答案链接

在这里插入图片描述
我的理解:在每一天我都要考虑卖股票,假设我在第i天卖就需要在1到i-1天中的股价最低的时候买入(所以在遍历数组时会不断更新最小值),就能取得当前天的最大值,这样每一天都会有一个相应的最大值,取最大的那一个就可以了(所以遍历数组时只需要比当前max大才会更新max)。

94题:二叉树的中序遍历
在这里插入图片描述
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
    *returnSize = 0;
    int* res = malloc(sizeof(int) * 501);
    struct TreeNode** stk = malloc(sizeof(struct TreeNode*) * 501);//定义数组模拟栈,栈内存放二叉树结点指针
    int top = 0;//一开始指向零
    while (root != NULL || top > 0) {//如果栈内没有元素并且root为空就退出循环
        while (root != NULL) {//一直往里面加左子树,直到左子树为空
            stk[top++] = root;
            root = root->left;
        }
        root = stk[--top];
        res[(*returnSize)++] = root->val;//returnSize作为一个指针,起到全局变量的作用
        root = root->right;
    }
    return res;
}

19:删除倒数第n个节点

在这里插入图片描述

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){**//方法一**
struct ListNode* q=head;
int count=0;
struct ListNode *k=q;
while(q!=NULL){//链表长度的计算
count++;
q=q->next;
}
q=head;
int s=count-n+1;//这就是表示要删除的位置
if(s==1) return head->next;//如果删除的是第一个,直接返回下一个
count=1;
while(count!=s){//k指向被删除的前一个元素,q指向被删除的
    k=q;
    q=q->next;
    count++;
    
}
k->next=q->next;//后面的链表连接上前面的
return head;
}

此代码就是遍历长度,找到要删除的位置,然后删除,注意删除的三种情况也就是边界情况的处理,如删除第一个。注(题目传入的链表至少有一个元素)

方法二

用两个指针,rear从n+1出发,front从1出发,当rear指向最后一个节点的下一个节点,front恰好指向要被删除的节点。(因为front从1走到count-n+1,rear从x走到count+1,就可以得出x比1多n)

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode* rear=head;
struct ListNode* front=rear;
struct ListNode* c=front;//c用来记录要被删除的节点的前一个节点。
while(n>0){
    rear=rear->next;
    n--;
}
/*如果后面的指针直接指向null,说明指向到最后一个节点的下一个,说明移动了n个长度,其实也就是要删除第一个节点*/
if(rear==NULL) return head->next; 
while(rear!=NULL){//当rear指向null,此时front恰好指向要被删除的,c指向要被删除的节点的前一个节点。
    c=front;
    front=front->next;
    rear=rear->next;
}
c->next=front->next;
return head;
}

心得:事实上,如果删除的是第一个节点,这两种写法都会需要进行特殊处理,而加入一个头节点就可以统一所有情况。所以最好是不要用一个指针来记录要被删除的前一个,而是直接加入头节点统一所有情况。具体看官方题解。

24:

在这里插入图片描述

struct ListNode* swapPairs(struct ListNode* head){//递归
if(head==NULL||head->next==NULL) return head;
struct ListNode *one=head;
struct ListNode *two=head->next;
struct ListNode *three=two->next;
two->next=one;
one->next=swapPairs(three);
return two;
}
struct ListNode* swapPairs(struct ListNode* head) {//迭代
    struct ListNode dummyHead;
    dummyHead.next = head;
    struct ListNode* temp = &dummyHead;
    while (temp->next != NULL && temp->next->next != NULL) {
        struct ListNode* node1 = temp->next;
        struct ListNode* node2 = temp->next->next;
        temp->next = node2;
        node1->next = node2->next;
        node2->next = node1;
        temp = node1;
    }
    return dummyHead.next;
}

61 旋转链表

在这里插入图片描述

struct ListNode* rotateRight(struct ListNode* head, int k){
    if(head==NULL) return head;
int count=0;
struct ListNode* jxy=head;
while(jxy->next!=NULL){
    jxy=jxy->next;
    count++;
}//此时jxy指向最后一个结点
count++;//+1才是正确的节点数量
jxy->next=head;//形成环
int c=0;
c=k%count;//k如果是count整数倍相当于没有移动,所以取余
c=count-c;//count-c的下标就是新的头节点的前一个节点
int i=1;
jxy=head;
while(i!=c){//让jxy移动到新的头节点的前一个节点
jxy=jxy->next;
i++;
}
struct ListNode* newhead=jxy->next;
jxy->next=NULL;
return newhead;
}

心得:链表一般考虑快慢指针,双指针,成环,翻转来做。这道题形成环以后找到新的头节点就可以了。

82

在这里插入图片描述

struct ListNode* deleteDuplicates(struct ListNode* head) {
    if (!head) {
        return head;
    }

    struct ListNode* dummy = malloc(sizeof(struct ListNode));
    dummy->next = head;

    struct ListNode* cur = dummy;
    while (cur->next && cur->next->next) {//为空直接退出,此时不会有重复的元素。
        if (cur->next->val == cur->next->next->val) {//如果cur后面的第一个和第二个相等
            int x = cur->next->val;//记录下第一个的值
            while (cur->next && cur->next->val == x) {//把为x的全部删除掉
                cur->next = cur->next->next;
            }
        } else {//如果不相等说明此时不需要进行处理,直接让cur后移
            cur = cur->next;
        }
    }
    return dummy->next;
}

198

在这里插入图片描述

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty()) {
            return 0;
        }
        int size = nums.size();
        if (size == 1) {
            return nums[0];
        }
        vector<int> dp = vector<int>(size, 0);
        dp[0] = nums[0];//dp[0]代表偷第一家能得到的最多的钱
        dp[1] = max(nums[0], nums[1]);//dp[1]代表着第一家和第二家选一家大的偷
        for (int i = 2; i < size; i++) {
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }//在i位置偷到的最大的钱可能来自于不偷这家(dp【i-1】),偷这家并且选择
        //加上dp【i-2】,谁大选谁,这样就可以得到在i位置能偷到的最多的金额。
        return dp[size - 1];
    }
};

206反转链表

struct ListNode* reverseList(struct ListNode* head){
if(head==NULL||head->next==NULL) return head;
struct ListNode *q1=NULL;
struct ListNode* q2=head;
struct ListNode * q3=head->next;
struct ListNode * q4=head->next->next;
while(1){
    q2->next=q1;
    q3->next=q2;
    q1=q2;
    q2=q3;
    q3=q4;
    if(q4==NULL) break;
    q4=q4->next;
}
return q2;
}

92反转链表二

在这里插入图片描述

struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
if(head->next==NULL) return head;//只有一个直接返回
struct ListNode* virtualhead=malloc(sizeof(struct ListNode));//加一个虚拟节点
virtualhead->next=head;//加虚拟节点的好处在于,翻转整个链表的逻辑不用重新写
struct ListNode* pre=virtualhead;//pre一直指向待处理区域的前一个
for(int i=1;i<left;i++){//pre后移
    pre=pre->next;
}
struct ListNode* cur=pre->next;//cur在这里赋值过后就不会再变化

   for(int i=1;i<=right-left;i++){//对于待处理区域的每一个元素,每次都放一个到最前面
        struct ListNode * curnext=cur->next;//这样就可以实现翻转
    cur->next=curnext->next;
    curnext->next=pre->next;
    pre->next=curnext;
   }

return virtualhead->next;
}

143重排链表

在这里插入图片描述


void reorderList(struct ListNode* head) {
    if (head == NULL) {
        return;
    }
    struct ListNode* vec[40001];
    struct ListNode* node = head;
    int n = 0;
    while (node != NULL) {
        vec[n++] = node;
        node = node->next;
    }
    int i = 0, j = n - 1;
    while (i < j) {
        vec[i]->next = vec[j];
        i++;
        if (i == j) {//对于偶数这种情况已经弄好了直接退出函数
            break;
        }
        vec[j]->next = vec[i];
        j--;
    }
    vec[i]->next = NULL;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值