当前位置:   article > 正文

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

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

友友们,通过前两天的练习和坚持,我们数组部分的算法题已经学完了,不知道大家理解得怎么样,可以多做题多思考,题目做不出来不要死磕看看题解学习一下别人的思路哦! 

移除链表元素:

203. 移除链表元素 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/remove-linked-list-elements/submissions/477690164/题目思路:做链表这部分题目的一个前提就是大家要先掌握链表的知识,知道链表是怎样存储数据的。在移除链表元素这道题中我们要考虑头节点是否与要移除的元素相等,若相等就要移除头节点,那么就要更新头节点,还有一种方法是设置一个虚拟头节点。

  • 原链表删除元素:在本题中首先我们要判断头节点 head 指向的元素是否需要删除,若需要就将头节点删除将头节点 next 域中存放的地址对应的节点更新为头节点。如果要删除的元素不是头节点,就将此节点删除将下一节点的地址放入上个结点的 next 域中,此过程中指针一直在向后移动。

具体代码如下:

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* removeElements(ListNode* head, int val) {
  14. ListNode* temp ;
  15. while(head != NULL && head->val == val){
  16. temp = head;
  17. head = head->next;//链表中的第一个元素作为头指针,如果头指针指向元素与目标值相等就将头指针指向元素删除并将next元素作为头指针
  18. delete temp;
  19. }//用while是因为不一定有几个与val相同的值,要确保所有与目标值相等的元素都删除
  20. //如果头指针指向元素与目标值不相等,就定义一个指针指向头节点
  21. ListNode* cur = head;
  22. while(cur != NULL && cur->next != NULL){
  23. if(cur->next->val == val){
  24. temp = cur->next;
  25. cur->next = cur->next->next;//将与目标值相等的元素删除,并将下一个元素的地址放入前一个元素的next域
  26. delete temp;
  27. }else{
  28. cur = cur->next;//将指针向后移动
  29. }
  30. }
  31. return head;
  32. }
  33. };
  •  虚拟头节点方法:定义一个虚拟头节点,将虚拟头节点的 next 域指向链表的头节点,这样就将头结点当成普通节点一样删除,不需要单独处理头节点了。
  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* removeElements(ListNode* head, int val) {
  14. ListNode* dummyhead = new ListNode(0);//定义一个虚拟头节点
  15. dummyhead->next = head;
  16. ListNode* cur = dummyhead;//为什么从指向dummyhead->next开始,是因为如果从指向它开始的话,相当于从指向头节点开始,如果要删除头结点的话还是要单独操作,就会增加时间复杂度。
  17. while(cur->next != NULL){
  18. if(cur->next->val == val){
  19. ListNode* temp = cur->next;
  20. cur->next = cur->next->next;
  21. delete temp;
  22. }else{
  23. cur = cur->next;
  24. }
  25. }
  26. return dummyhead->next;
  27. }
  28. };

设计链表 :

707. 设计链表 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/design-linked-list/description/题目思路:

 本题依然是用虚拟头结点的方法,结合C语言数据结构中的链表的各种操作,我们看一下具体代码。

  1. class MyLinkedList {
  2. public:
  3. struct LinkedNode {//定义链表节点结构体
  4. int val;
  5. LinkedNode* next;
  6. LinkedNode(int val):val(val), next(nullptr){}
  7. };
  8. //初始化链表
  9. MyLinkedList() {//链表属性的定义在下方
  10. dummyhead = new LinkedNode(0);//定义一个虚拟头节点
  11. size = 0;//链表长度
  12. }
  13. int get(int index) {
  14. if(index > (size - 1) || index < 0){//如果下标不合法就返回-1
  15. return -1;
  16. }
  17. LinkedNode* cur = dummyhead->next;//cur指针从头节点开始移动
  18. while(index--){//不能是--index,因为如果index为0,指的是链表头节点,先自减再进入循环的话就少一个节点
  19. cur = cur->next;//如果index等于0,也就是只有一个节点,那么循环结束后cur指向的是那个唯一的节点,如果cur从虚拟头节点开始遍历,最后cur指向的是目标元素的前一个
  20. }
  21. return cur->val;
  22. }
  23. void addAtHead(int val) {
  24. LinkedNode* newnode = new LinkedNode(val);
  25. newnode->next = dummyhead->next;
  26. dummyhead->next = newnode;
  27. size++;
  28. }
  29. void addAtTail(int val) {
  30. LinkedNode* newnode = new LinkedNode(val);
  31. LinkedNode* cur = dummyhead;
  32. while(cur->next != nullptr){
  33. cur = cur->next;
  34. }
  35. cur->next = newnode;
  36. size++;
  37. }
  38. void addAtIndex(int index, int val) {
  39. if(index > size||index < 0) return;
  40. LinkedNode* newnode = new LinkedNode(val);
  41. LinkedNode* cur = dummyhead;
  42. while(index--){//遍历链表直到下表为index的元素为止
  43. cur = cur->next;
  44. }
  45. newnode->next = cur->next;
  46. cur->next = newnode;
  47. size++;
  48. }
  49. void deleteAtIndex(int index) {
  50. if(index >= size||index < 0) return;
  51. LinkedNode* cur = dummyhead;
  52. while(index--){
  53. cur = cur->next;
  54. }
  55. LinkedNode* temp = cur->next;
  56. cur->next = cur->next->next;
  57. delete temp;
  58. temp = nullptr;
  59. size--;
  60. }
  61. void printLinkedList() {
  62. LinkedNode* cur = dummyhead;
  63. while (cur->next != nullptr) {
  64. cout << cur->next->val << " ";
  65. cur = cur->next;
  66. }
  67. cout << endl;
  68. }
  69. private:
  70. int size;
  71. LinkedNode* dummyhead;
  72. };
  73. /**
  74. * Your MyLinkedList object will be instantiated and called as such:
  75. * MyLinkedList* obj = new MyLinkedList();
  76. * int param_1 = obj->get(index);
  77. * obj->addAtHead(val);
  78. * obj->addAtTail(val);
  79. * obj->addAtIndex(index,val);
  80. * obj->deleteAtIndex(index);
  81. */

反转链表 :

206. 反转链表 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/description/解题思路 :

  • 双指针法:定义两个指针,一个pre指向空,一个cur指向头节点,只要cur不指向空,就将箭头翻转,但是在这之前,要将cur->next保存下来否则就找不到了,在移动指针的时候要先将pre指向cur,再将cur指向cur->next(也就是临时存放cur->next的指针),移动到最后就是cur指向空,pre指向链表反转后的头节点,最后返回pre即可。

具体代码如下:

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* reverseList(ListNode* head) {
  14. ListNode* pre = NULL;
  15. ListNode* cur = head;
  16. ListNode* temp;
  17. while(cur != NULL){
  18. temp = cur->next;
  19. cur->next = pre;//反转链表
  20. pre = cur;//一定要先将pre指向cur,再将cur指向下一个,否则就找不到cur了
  21. cur = temp;
  22. }
  23. return pre;
  24. }
  25. };
  • 递归法: 递归的方法其实就是对双指针法的一个简化,思路一模一样。
  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* reverseList(ListNode* head) {
  14. return reverse(head,NULL);//传入初始实参,初始化时cur指向头节点,pre指向空
  15. }
  16. ListNode* reverse(ListNode* cur,ListNode* pre){
  17. if(cur == NULL){
  18. return pre;
  19. }
  20. ListNode* temp = cur->next;
  21. cur->next = pre;
  22. return reverse(temp,cur);//pre指向cur,cur指向temp
  23. }
  24. };

心得:今天学的是链表这部分,因为我的数据结构还没学完,而且学的还是C语言版的,所以导致今天学的有些吃力,C++中的一些语法盲区还导致了编译错误,改bug浪费了好多时间 ,心态快崩了,接下来我要做的是去补一下C++的语法,还有vs的调试怎么调,以后有时间的话还是要实现以下完整的代码,主要是先把算法过一遍,了解一下优化的算法,开拓一下思维。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/52763
推荐阅读
相关标签
  

闽ICP备14008679号