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

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

知识点

链表

  • 定义链表结构体:
struct ListNode {
    int val;
    ListNode *next; // 指向ListNode类型的指针,next中存放指向一块存放ListNode型对象地址
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

指针

  • 定义
    • Type *instance;
    • instance: 存放指向一块Type型对象地址
    • 未初始化:拥有不确定值。因此建议都初始化。
  • 利用指针访问对象
    • &
      • 引用:int i = 10; int &a = i; ,紧跟类型名;
      • 取地址符:int *p; p = &i;,取出变量的地址;
    • *
      • int *p;:代表指针;
      • *p = 10 :解引用符,访问p指向对象;
  • 空指针
    • int *p = nullptr;
    • int *p = 0 / NULL;

题解

203.移出链表元素

解法:用原链表操作 & 加虚拟头结点;
心路历程:已经忘了链表的具体实现,又翻了数据结构书捡起来的。看题知道流程什么样,一上手连指针的概念都忘了。
代码:
结构体声明:

struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};
  1. 原链表操作
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
		while (head != NULL && head->val == val) {
			ListNode* tmp = head;    // 操作头元素
			head = head->next;
			delete tmp;
		}
		// 至此头元素不再会被摘掉,因此头指针须保留,用于返回
		ListNode* item = head;   // 两个留一个,另一个用于遍历链表
		while (item != NULL && item->next != NULL) {
			if (item->next->val == val) {
				ListNode* tmp = item->next;
				item->next = tmp->next;
				delete tmp;
			}
			else item = item->next;
		}
		return head;
    }
};
  1. 设虚拟头指针
// 不规范版
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
		ListNode* virt = new ListNode(0, head); // 挂在真正头结点前
		ListNode* res = virt;  // 一个保存头指针,一个遍历
		while (virt->next != NULL) {
			if (virt->next->val == val) {
				ListNode* tmp = virt->next;
				virt->next = tmp->next;
				delete tmp;
			}
			else virt = virt->next;
		}
		head = res->next; // 返回真正头指针
        delete res; // 销毁虚拟头指针
        // 不能销毁virt:空指针没问题(最后一个元素不等于val),
        // 如果是最后一个有效元素(virt->next->val == val)返回将错误
		return head;
    }
};
// 规范版
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
		ListNode* virt = new ListNode(0, head); // 挂在真正头结点前
		// 上述代码知:while中链表遍历指针不能delete,如果选动态内存分配new出的指针遍历,
		// 意味着不能delete;可 new出的空间最好delete释放掉,所以不能选virt.
		ListNode* res = virt;  // so,res遍历,virt保存(最后销毁)
		while (res->next != NULL) {
			if (res->next->val == val) {
				ListNode* tmp = res->next;
				res->next = tmp->next;
				delete tmp;
			}
			else res = res->next;
		}
		head = virt->next; // 返回真正头指针
        delete virt; // 销毁虚拟头指针
		return head;
    }
};

707.设计链表

  • 思路:起初没想到:用location记录位置走的有点麻烦,把自己搞蒙了
  • 实现:
class MyLinkedList {
private:
    int _size;
    LinkedList* _dummyHead;
    LinkedList* _p;
public:
	struct LinkedList {
		int val;
		LinkedList *next;
    	LinkedList(int val) {
			this->val = val;
			this->next = 0;
		}
	};
	MyLinkedList() {
		_dummyHead = new LinkedList(-1);
		_size = 0; // 结点个数
		_p = _dummyHead; // 虚拟头结点
	}
    int get(int index) {
    	_p = _dummyHead;
    	if (index > _size-1) return -1;
    	int loc = -1;
		while (_p->next != 0) {
			_p = _p->next;
			loc++;
			if (loc == index) break;
		}
		return _p->val;
    }
    void addAtHead(int val) {
    	_p = _dummyHead;
    	LinkedList *tmp = new LinkedList(val);
    	tmp->next = _p->next;
		_p->next = tmp;
		_size++;
       	tmp = 0;
       	delete tmp;
		return;
    }
    void addAtTail(int val) {
		_p = _dummyHead;
		LinkedList *tmp = new LinkedList(val);
		while (_p->next != 0) {
			_p = _p->next;
		}
		_p->next = tmp;
		_size++;
		tmp = 0;
		delete tmp;
    }
    void addAtIndex(int index, int val) {
    	if (index <= 0) return this->addAtHead(val); // index<=0
    	if (index == _size) return this->addAtTail(val); // index 在末尾
    	if (index > _size) return;
    	_p = _dummyHead;
    	int loc = -1;
		while (index--) {
			_p = _p->next; 
		}
		LinkedList *tmp = new LinkedList(val);
		tmp->next = _p->next;
		_p->next = tmp;
		_size++;
		tmp = 0;
		delete tmp;
		return;
    }
    void deleteAtIndex(int index) {
    	if (index > _size-1) return;
		_p = _dummyHead;
		while (index--) {
			_p = _p->next;
		}
		LinkedList *tmp = _p->next;
		_p->next = tmp->next;
		delete tmp;
		_size--;
		return;
    }
};

206.反转链表

  • 思路:快慢指针
  • 做法:代码随想录
  • 实现
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* low = nullptr; // 慢指针要比快指针慢一拍(某一时刻二者有一个元素间隔),用于快指针指向慢指针代表的前一个元素
        ListNode* fast = head;
        ListNode* tmp = nullptr; // 用于保存快指针的下一步
        while(fast != nullptr) {
            tmp = fast->next;
            fast->next = low;
            low = fast;
            fast = tmp;
        }
        return low;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值