代码随想录算法训练营第三天 | 203.移除链表元素,206. 反转链表,707. 设计链表

题目一:
203. 移除链表元素

思路:

1. 设定一个临时指针temp,逐步遍历链表,遇到符合val的结点就删除

2. 因为头结点为 val 时,需要一个指向头结点的结点,所以设定一个虚拟头结点,并令 temp 指向它

代码:

难点在于头结点的解法和不是头结点的解法能不能混合?如何混合?

    1 	class Solution {
    2 	public:
    3 	    ListNode* removeElements(ListNode* head, int val) {
    4 	        //创造虚拟头结点,防止头结点为要删除的值,导致需要两种删除结点的方法
    5 	        ListNode* list = new ListNode();
    6 	        list->next = head;
    7 	        //创造一个指针,遍历链表
    8 	        ListNode* temp = list;
    9 	        //如果要删除元素,需要知道被删除结点的的前一个结点,所以使用temp->next
   10 	        while(temp->next != NULL)
   11 	        {
   12 	            if(temp->next->val == val)
   13 	            {
   14 	                //ListNode* freeNode = temp->next;
   15 	                temp->next = temp->next->next;
   16 	                //free(freeNode);
   17 	            }
   18 	            else temp = temp->next;
   19 	        }
   20 	        return list->next;
   21 	    }
   22 	};

题目二:
206. 反转链表

初见思路:

1.开始想了两三种思路,但待到开始敲代码时才发现无法指向前一个结点。过了二十多分钟,想了一个三指针的思路,并在纸上模拟成功,就开敲了

代码1:

其实只能算不完美的双指针解法,我没能结合将头结点的解法与非头结点的解法混合在一起

而下面的代码2为双指针解法,看完才觉得妙,非常妙!

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr) return head;
        if(head->next == nullptr) return head;

        ListNode* c1 = head;
        ListNode* c2 = c1->next;
        ListNode* c3 = c2->next;
 
        c2->next = c1;
        c1->next = nullptr;
        if(c3 == nullptr) return c2;
        while(c3 != nullptr)
        {
            c1 = c2;
            c2 = c3;
            c3 = c3->next;
            c2->next = c1;
        }
        c2->next = c1;
        return c2;
    }
};
代码2:
    1 	class Solution {
    2 	public:
    3 	    ListNode* reverseList(ListNode* head) {
    4 	        //从头结点开始,不用单独考虑头结点是否为空
    5 	        ListNode* c1 = nullptr;
    6 	        ListNode* c2 = head;
    7 	        while(c2 != nullptr)
    8 	        {
    9 	            //定义一个指针,保存c2后面的地址
   10 	            ListNode* c3 = c2->next;
   11 	            c2->next = c1;
   12 	            c1 = c2;
   13 	            c2 = c3;
   14 	        }
   15 	        //当结束循环,c2指向null,c1指向尾结点
   16 	        return c1;
   17 	    }
   18 	};

题目3: 

707. 设计链表

初见:

1. 之前敲过便以为随随便便都可以,但之后却是无尽的debug

2.看视频后解决恍然大悟

思路:

1. 定义结构体

2. 设定私有属性虚拟头结点_dummyHead 和成员长度_size

3. 插入函数需要让_size的范围加1,不然当插入尾结点之后会错误

代码3:
class MyLinkedList {
public:
    //构造链表的属性    
    typedef struct ListNode{        
        int val;         
        struct ListNode *next;         
        ListNode(int val):val(val),next(nullptr){} //构造函数兼初始化     
    };
    MyLinkedList(){         
        _dummyHead = new ListNode(0); //定义虚拟头结点,初始化链表        
        _size = 0;     
    }          
        //因为虚拟头结点为成员变量,所以成员函数可以直接访问,参数不用添加虚拟头结点     
    int get(int index) {        
        if(index >= 0 && index <= _size)
        {
            ListNode* cur = _dummyHead->next;
            //当index为0时循环停止
            while(index)
            {
                cur = cur->next;
                index--;
            }
            return cur->val;
        }
        return -1;
    }    
    void addAtHead(int val) {      
        ListNode* new_Node = new ListNode(val);
        new_Node->next = _dummyHead->next;
        _dummyHead->next = new_Node;
        _size++; //链表长度加一
    }     
    void addAtTail(int val) { 
        //防止头结点不存在,若为_dummyHead->next,且头结点为空,就会报错
        //因为结合whlie循环,会重复访问nullptr     
        ListNode* cur = _dummyHead;
        //直到指向尾节点停止,因为尾结点指向nullptr
        while(cur->next != nullptr)
        {
            cur = cur->next;
        }
        ListNode* new_Node = new ListNode(val);
        cur->next = new_Node;
        _size++;
    }         
    void addAtIndex(int index, int val) {     
        //加一是因为新元素会变成链表的末尾,cur = 末尾,index = _size + 1;,所以要+1 index才能访问 
    if(index >= 0 && index <= _size + 1)
        {
            ListNode* cur = _dummyHead;
            //当index为0时循环停止
            while(index)
            {
                cur = cur->next;
                index--;
            }
            ListNode* new_Node = new ListNode(val);
            new_Node->next = cur->next;
            cur->next = new_Node;
            _size++;
        }
    }        
    void deleteAtIndex(int index) {      
        if(index >= 0 && index <= _size)
        {
            //同理,需要考虑头结点
            ListNode* cur = _dummyHead;
            while(index)
            {
                cur = cur->next;
                index--;
            }
            ListNode* temp = cur->next;
            cur->next = cur->next->next;
            delete temp;
            temp = nullptr;
            _size--;
        }
    }
private:     
    ListNode* _dummyHead; //定义虚拟头结点     
    int _size; //记录链表当前长度 
};
/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值