您现在的位置是:首页 >技术教程 >代码随想录算法训练营第三天|203.移除链表元素 707.设计链表 206.反转链表网站首页技术教程

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

禹泽. 2023-06-01 20:00:02
简介代码随想录算法训练营第三天|203.移除链表元素 707.设计链表 206.反转链表

目录

LeeCode 203.移除链表元素

解法一:常规解法

解法二:设置虚拟头结点

LeeCode 707.设计链表  

LeeCode 206.反转链表

解法一:双指针法

解法二:递归法

总结


LeeCode 203.移除链表元素

力扣题目链接

解法一:

常规思路:遍历链表寻找符合条件的结点,将该结点的前一个结点的后续指针 指向 这个结点的下一个结点,并删除当前结点。

若需要删除头结点,因为头结点没有上一个结点,所以需要单独考虑这种情况。此时,将头结点向后移动一位,并删除原头结点即可。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        while(head != NULL && head->val ==val){
    		ListNode* tmp = head;
    		head = head->next;
    		delete tmp;
		}
		ListNode* cur = head;
		while(cur != NULL && cur->next != NULL){
			if(cur->next->val == val){
				ListNode* tmp = cur->next;
				cur->next = cur->next->next;
				delete tmp;
			}
			else{
				cur = cur->next;
			}
		}
    	return head;

    }
};

时间复杂度:O(n)

第10行中 while 的条件,如果写成  cur->next != NULL && cur != NULL 会报错(如下,但不理解),不过好在正常人都不会这样写。

Line 10: Char 14: runtime error: member access within null pointer of type 'ListNode' (solution.cpp) SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:29:14

解法二:

为了避免对头结点的特殊处理,可以通过构造虚拟头结点来解决将其放在头结点之前,最后删除这个虚拟头结点。

class Solution {
public:
    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* tmp = cur->next;
        		cur->next = cur->next->next;
        		delete tmp;
			}
			else{
				cur = cur->next;
			}
		}
		head = dummyHead->next;
		delete dummyHead;
		return head;
    }
};

时间复杂度:O(n)


LeeCode 707.设计链表  

力扣题目链接

 构造函数来实现一些常见的操作,要求对链表的定义比较熟悉。

需要注意的是本题的index是从0开始。

class MyLinkedList {
public:
    struct LinkedNode{
        int val;
        LinkedNode* next;
        LinkedNode(int val):val(val),next(nullptr){}

    };
    MyLinkedList() {
    	_dummyHead = new LinkedNode(0);//定义一个虚拟的头结点 
		_size = 0; 
    }
    
    int get(int index) {
    	if(index > (_size - 1) || index < 0){
    		return -1;
		} 
		LinkedNode* cur = _dummyHead->next;
		while(index--){
			cur = cur->next;
		}
		return cur->val;
    }
    
    //在链首插入一个结点 
    void addAtHead(int val) {
    	LinkedNode* newNode = new LinkedNode(val);
		newNode->next = _dummyHead->next;
		_dummyHead->next = newNode; 
    	_size++; 
    }
    
    //在链尾插入一个结点 
    void addAtTail(int val) {
    	LinkedNode* newNode = new LinkedNode(val);
    	LinkedNode* cur = _dummyHead;
    	while(cur->next != nullptr){
    		cur = cur->next;
		}
		cur->next = newNode;
    	_size++;
    }
    
	//将一个值为val的结点插入到链表中下标为index的结点前
	//如果index等于链表长度,该结点加在链尾
    void addAtIndex(int index, int val) {
    	if(index > _size) return;//如果index比长度更大,该结点不会插入到链表中
		if(index < 0) index = 0;//如果index小于0,将该结点插入到表头 
		LinkedNode* newNode = new LinkedNode(val);
		LinkedNode* cur = _dummyHead;
		while(index--){
			cur = cur->next;
		} 
		newNode->next = cur->next;
		cur->next = newNode;
		_size++;
    }
    
    //删除第index个结点,若index大于链表长度,直接return 
    void deleteAtIndex(int index) {
    	if(index >= _size || index < 0)  return;
		LinkedNode* cur = _dummyHead;
		while(index--){
			cur = cur->next;
		} 
		LinkedNode* tmp = cur->next;
		cur->next = cur->next->next;
		delete tmp;
		_size--;
    }
private:
    int _size;
    LinkedNode* _dummyHead;


};

/**
 * 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);
 */

LeeCode 206.反转链表

力扣题目链接​​​​​​

解法一:双指针法

思路:改变链表的next指针的指向,直接将链表反转,而不用重新定义一个新的链表。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* temp;//存储反转后的下一个结点 
    	ListNode* cur = head;
    	ListNode* pre = NULL;
		while(cur){
			temp = cur->next;
			cur->next = pre;//反转指针 
			pre = cur;
			cur = temp;
		} 
		return pre;
    }
};

时间复杂度:O(n)

解法二:递归法

思路:把对指针反向的操作写成递归。(本质和双指针法是一样的)

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
    	return reverse(NULL,head); 
    }
    ListNode* reverse(ListNode* pre,ListNode* cur){
    	if(cur == NULL) return pre;
    	ListNode* temp = cur->next;
    	cur->next = pre;
    	return reverse(cur,temp);
	}
};

时间复杂度:O(n) 


总结

1.感谢:说实话,本学期刚学过链表,考试和作业也都写过关于定义链表和链表反转的题目,但当时只是应付作业,仅以完成为目的,没深入思考解题方法的内在逻辑,真到动手实践时才发现一堆问题o(╥﹏╥)o。以后还是尽量弄懂,不能光写出来伪代码大体理解思想就放过自己,而是得亲自动手去编译运行,遇到问题、解决问题之后才算真懂。

2.链表的题画图会更容易帮助理解,尤其是多个指针都在移动,但作者能力有限,画的图只能自己看懂,就不放上来了。

3.今天的题目思路比较容易理解,代码实现起来有一定难度,还得继续努力。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。