代码随想录第三天 leetcode 203、707、206

链表

首先复习一下链表,并与数组做出对比。

  • 常用的为单向链表,每个结点由两部分组成:一个是当前结点的值,另一个是指向下一个结点的指针
  • 链表的操作:链表的查询的时间复杂度是O(n),而增删操作的时间复杂度为O(1),所以适合频繁增删的场景。
    对比
  • C++中链表的定义:
ListNode(){
	int val;
	ListNode* next;
	ListNode(int x):val(x) , next(NULL){}
};

LeetCode 203.移除链表元素

移除链表元素主要考虑到移除头节点时的特殊情况,所以使用虚拟头结点让处理头节点时不用单独处理,另一个需要注意的地方记得使用一个temp保存一下需要删除结点之后的结点。下面直接给出代码:

ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* cur = dummyhead;
        while(cur->next != NULL){
            if(cur->next->val == val){
                ListNode* temp = cur->next;
                cur->next = cur->next->next;
                delete temp;
            }else{
                cur = cur->next;
            }
        }
        return dummyhead->next;
    }

LeetCode 707. 设计链表

设计链表一个是对代码的掌控能力,与之前模拟螺旋矩阵一样需要注意的细节比较多;另一个是对链表本身基础的掌控。
需要注意的点:

  • 本题需要自己定义链表结构体并定义及初始化类成员变量
  • 参考卡哥的代码,因为涉及删除的操作,所以在成员变量提前定义好一个虚拟头结点
  • 其实想好index的值之后,本题难度不大
  1. 首先定义好一个链表,并初始化一个链表:
	struct ListNode{
        int val;
        ListNode* next;
        ListNode(int x):val(x),next(NULL) {}
    };
	MyLinkedList() {
        dummyhead = new ListNode(0);
        size = 0;
    }
private:
	ListNode* dummyhead;
	int size;
  1. 编写单独的函数:
	//获取index的值
	int get(int index) {
        if(index < 0 || index >= size) return -1;
        ListNode* cur = dummyhead->next;
        while(index--){
            cur = cur->next;
        }
        return cur->val;
    }
    //在头添加
    void addAtHead(int val) {
        ListNode* newnode = new ListNode(val);
        newnode->next = dummyhead->next;
        dummyhead->next = newnode;
        size++;
    }
    //在尾添加
    void addAtTail(int val) {
        ListNode* newnode = new ListNode(val);
        ListNode* cur = dummyhead;
        while(cur->next != NULL){
            cur = cur->next;
        }
        cur->next = newnode;
        size++;
    }
    //在指定index添加
    void addAtIndex(int index, int val) {
        if(index > size) return;
        ListNode* newnode = new ListNode(val);
        ListNode* cur = dummyhead;
        while(index--){
            cur = cur->next;
        }
        newnode->next = cur->next;
        cur->next = newnode;
        size++;
    }
    //在指定位置删除,包括头尾
    void deleteAtIndex(int index) {
        if(index < 0 || index >= size) return;
        ListNode* cur = dummyhead;
        while(index--){
            cur = cur->next;
        }
        ListNode* temp = cur->next;
        cur->next = cur->next->next;
        delete temp;
        size--;
    }

因为比较基础,所以熟练即可。

LeetCode 206. 反转链表

力扣上这题标的简单,我觉得其实不简单。两种方法:双指针和递归。

  • 双指针法:使用双指针法时,定义一个pre和一个cur,因为链表的特殊性,需要一个结点一个结点的处理。逻辑就是处理cur结点时,断开cur与下一个结点,并使cur的下一个结点指向pre。然后pre与cur同时向后移位。特别注意:pre与cur指向的结点只表示两者当前所在的结点,与他们指针域指向的结点无关,听起来有点绕,一开始想明白了双指针的逻辑,没想明白代码逻辑。
    下面给出代码:
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = NULL;
        ListNode* cur = head;
        while(cur){
            ListNode* temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
};
  • 递归法:使用递归法时,一定要先确定递归函数的输入,以及在什么条件下跳出递归循环。递归的过程与双指针的过程一样,所以递归的输入就是pre和cur两个指针;当模拟过程到最后一次循环时,pre指向的是最后一个有值的结点,而cur指向的是一个空结点NULL,所以跳出递归的条件就是cur == NULL并且返回pre结点。下面给出递归的函数:
ListNode* reverse(ListNode* pre , ListNode* cur){
	if(cur == NULL) return pre;
	ListNode* temp = cur->next;
	cur->next = pre;
	return reverse(cur,temp);
}

递归函数中就不需要写像双指针法中指针移位的逻辑,直接将curcur->next的之间断开,然后递归。
下面就是主函数:

	ListNode* reverseList(ListNode* head) {
        return reverse(NULL, head);
    }

坚持坚持坚持!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值