算法标题总结-链表

打印 上一主题 下一主题

主题 990|帖子 990|积分 2970

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1.环形链表

1.答案

  1. package com.sunxiansheng.arithmetic.day11;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 141. 环形链表
  5. *
  6. * @Author sun
  7. * @Create 2025/1/16 10:36
  8. * @Version 1.0
  9. */
  10. public class t141 {
  11.     public boolean hasCycle(ListNode head) {
  12.         // 快慢指针
  13.         ListNode slow = head;
  14.         ListNode fast = head;
  15.         while (fast != null && fast.next != null) {
  16.             slow = slow.next;
  17.             fast = fast.next.next;
  18.             // 只要相遇了,就是有环
  19.             if (slow == fast) {
  20.                 return true;
  21.             }
  22.         }
  23.         return false;
  24.     }
  25. }
复制代码
2.思绪

快慢指针,只要相遇,就有环
2.两数相加

1.答案

  1. package com.sunxiansheng.arithmetic.day11;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 2. 两数相加
  5. *
  6. * @Author sun
  7. * @Create 2025/1/16 10:39
  8. * @Version 1.0
  9. */
  10. public class t2 {
  11.     public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
  12.         // 结果的头节点
  13.         ListNode res = new ListNode(-1);
  14.         ListNode cur = res;
  15.         // 进位
  16.         int carry = 0;
  17.         // 遍历两个链表的指针
  18.         ListNode t1 = l1, t2 = l2;
  19.         // 只要两个链表有一个不为空就进行遍历
  20.         while (t1 != null || t2 != null) {
  21.             // 获取两个节点的值
  22.             int var1 = t1 == null ? 0 : t1.val;
  23.             int var2 = t2 == null ? 0 : t2.val;
  24.             // 求和
  25.             int sum = var1 + var2 + carry;
  26.             // 用完进位之后要恢复0
  27.             carry = 0;
  28.             // 判断是否要进位
  29.             if (sum > 9) {
  30.                 carry = sum / 10;
  31.                 sum = sum % 10;
  32.             }
  33.             // 给结果赋值
  34.             cur.next = new ListNode(sum);
  35.             cur = cur.next;
  36.             // 移动指针
  37.             if (t1 != null) {
  38.                 t1 = t1.next;
  39.             }
  40.             if (t2 != null) {
  41.                 t2 = t2.next;
  42.             }
  43.         }
  44.         // 检查是否还有没处理的进位
  45.         if (carry > 0) {
  46.             cur.next = new ListNode(carry);
  47.         }
  48.         return res.next;
  49.     }
  50. }
复制代码
2.效果

核心是有一个进位的字段,多注意即可
3.反转链表

1.答案

  1. package com.sunxiansheng.arithmetic.day12;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 206. 反转链表
  5. *
  6. * @Author sun
  7. * @Create 2025/1/17 09:56
  8. * @Version 1.0
  9. */
  10. public class t206 {
  11.     public ListNode reverseList(ListNode head) {
  12.         if (head == null) {
  13.             return null;
  14.         }
  15.         // 哨兵节点
  16.         ListNode dummy = new ListNode(0);
  17.         dummy.next = head;
  18.         // prev
  19.         ListNode prev = dummy;
  20.         // start
  21.         ListNode start = head;
  22.         // then
  23.         ListNode then = start.next;
  24.         while (start.next != null) {
  25.             start.next = then.next;
  26.             then.next = prev.next;
  27.             prev.next = then;
  28.             then = start.next;
  29.         }
  30.         return dummy.next;
  31.     }
  32. }
复制代码
2.思绪

起首需要有prev、start、then,然后只要start.next不为空,就进行反转
4.反转链表 II

1.答案

  1. package com.sunxiansheng.arithmetic.day12;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 92. 反转链表 II
  5. *
  6. * @Author sun
  7. * @Create 2025/1/17 09:52
  8. * @Version 1.0
  9. */
  10. public class t92 {
  11.     public ListNode reverseBetween(ListNode head, int left, int right) {
  12.         // 找到prev、start、then
  13.         // 哨兵节点
  14.         ListNode dummy = new ListNode(0);
  15.         dummy.next = head;
  16.         // 让cur指向left的前一个节点作为prev
  17.         ListNode cur = dummy;
  18.         for (int i = 0; i < left - 1; i++) {
  19.             cur = cur.next;
  20.         }
  21.         ListNode prev = cur;
  22.         ListNode start = cur.next;
  23.         ListNode then = start.next;
  24.         // 遍历次数
  25.         int count = right - left;
  26.         for (int i = 0; i < count; i++) {
  27.             start.next = then.next;
  28.             then.next = prev.next;
  29.             prev.next = then;
  30.             then = start.next;
  31.         }
  32.         return dummy.next;
  33.     }
  34. }
复制代码
2.思绪

找到prev、start、then,然后遍历次数为right - left
5.K 个一组翻转链表

1.答案

  1. package com.sunxiansheng.arithmetic.day12;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 25. K 个一组翻转链表
  5. *
  6. * @Author sun
  7. * @Create 2025/1/17 10:21
  8. * @Version 1.0
  9. */
  10. public class t25 {
  11.     public ListNode reverseKGroup(ListNode head, int k) {
  12.         // 哨兵节点
  13.         ListNode dummy = new ListNode(0);
  14.         dummy.next = head;
  15.         ListNode cur = dummy;
  16.         // 提前记录prev
  17.         ListNode prev = dummy;
  18.         // 循环翻转
  19.         while (true) {
  20.             // 先判断有没有一组
  21.             for (int i = 0; i < k; i++) {
  22.                 cur = cur.next;
  23.                 // 只要发现没有一组了,就返回结果
  24.                 if (cur == null) {
  25.                     return dummy.next;
  26.                 }
  27.             }
  28.             // 到这里就说明有一组,可以翻转链表
  29.             ListNode start = prev.next;
  30.             ListNode then = start.next;
  31.             reverseGroup(prev, start, then, k);
  32.             // 更新prev
  33.             prev = start;
  34.             // 更新cur
  35.             cur = prev;
  36.         }
  37.     }
  38.     /**
  39.      * 翻转一组链表
  40.      *
  41.      * @param prev
  42.      * @param start
  43.      * @param then
  44.      * @param k
  45.      */
  46.     private void reverseGroup(ListNode prev, ListNode start, ListNode then, int k) {
  47.         // 翻转次数
  48.         int count = k - 1;
  49.         for (int i = 0; i < count; i++) {
  50.             start.next = then.next;
  51.             then.next = prev.next;
  52.             prev.next = then;
  53.             then = start.next;
  54.         }
  55.     }
  56. }
复制代码
2.思绪

就是先判定剩下的元素够不够k个,如果够就进行反转,翻转之后要更新prev和cur
6.删除链表的倒数第 N 个结点

1.答案

  1. package com.sunxiansheng.arithmetic.day12;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 19. 删除链表的倒数第 N 个结点
  5. *
  6. * @Author sun
  7. * @Create 2025/1/17 10:44
  8. * @Version 1.0
  9. */
  10. public class t19 {
  11.     public ListNode removeNthFromEnd(ListNode head, int n) {
  12.         // 哨兵节点
  13.         ListNode dummy = new ListNode(0);
  14.         dummy.next = head;
  15.         ListNode cur = dummy;
  16.         // 求出一共有多少个节点
  17.         int count = 0;
  18.         while (cur.next != null) {
  19.             cur = cur.next;
  20.             count++;
  21.         }
  22.         // 倒数第n个节点的前一个节点的索引
  23.         int index = count - n;
  24.         cur = dummy;
  25.         while (index > 0) {
  26.             cur = cur.next;
  27.             index--;
  28.         }
  29.         // 目前cur指向了前一个节点,可以开始删除节点了
  30.         cur.next = cur.next.next;
  31.         return dummy.next;
  32.     }
  33. }
复制代码
2.思绪

就是先找到一共有多少个节点,再找到倒数第n个节点的前一个节点然后删除
7.删除排序链表中的重复元素 II

1.答案

  1. package com.sunxiansheng.arithmetic.day13;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 82. 删除排序链表中的重复元素 II
  5. *
  6. * @Author sun
  7. * @Create 2025/1/19 09:32
  8. * @Version 1.0
  9. */
  10. public class t82 {
  11.     public static ListNode deleteDuplicates(ListNode head) {
  12.         // 哨兵节点
  13.         ListNode dummy = new ListNode(300);
  14.         dummy.next = head;
  15.         ListNode cur = dummy;
  16.         // 记录前一个位置
  17.         ListNode pre = dummy;
  18.         while (cur.next != null) {
  19.             cur = cur.next;
  20.             if (cur.next == null || cur.val != cur.next.val) {
  21.                 pre = cur;
  22.             } else {
  23.                 // 到这就说明pre的后两个元素相同
  24.                 // 记录一下值
  25.                 int val = cur.val;
  26.                 while (cur.next != null && val == cur.next.val) {
  27.                     cur = cur.next;
  28.                 }
  29.                 pre.next = cur.next;
  30.                 cur = pre;
  31.             }
  32.         }
  33.         return dummy.next;
  34.     }
  35.     public static void main(String[] args) {
  36.         ListNode head = new ListNode(1);
  37.         head.next = new ListNode(1);
  38.         head.next.next = new ListNode(1);
  39.         head.next.next.next = new ListNode(2);
  40.         head.next.next.next.next = new ListNode(3);
  41.         deleteDuplicates(head);
  42.     }
  43. }
复制代码
2.思绪

就是有一个pre来记录前一个位置,每次循环都让cur先走一步,然后判定当前元素跟下一个元素是不是相同,如果不相同大概目前是最后一个元素,就让pre也指向cur,如果说当前元素跟下一个元素是相同的,那么就删除相同元素,最终让cur指向pre
8.旋转链表

1.答案

  1. package com.sunxiansheng.arithmetic.day13;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. import java.util.List;
  4. /**
  5. * Description: 61. 旋转链表
  6. *
  7. * @Author sun
  8. * @Create 2025/1/19 10:29
  9. * @Version 1.0
  10. */
  11. public class t61 {
  12.     public ListNode rotateRight(ListNode head, int k) {
  13.         if (head == null || head.next == null) {
  14.             return head;
  15.         }
  16.         // 哨兵节点
  17.         ListNode dummy = new ListNode(0);
  18.         dummy.next = head;
  19.         ListNode cur = dummy;
  20.         // 计算链表总长度
  21.         int length = 0;
  22.         while (cur.next != null) {
  23.             cur = cur.next;
  24.             length++;
  25.         }
  26.         // 如果余数为0,则直接返回
  27.         if (k % length == 0) {
  28.             return head;
  29.         }
  30.         // 记录链表末尾元素
  31.         ListNode end = cur;
  32.         // 移动到正数第length - k % length个位置
  33.         int index = length - k % length;
  34.         cur = dummy;
  35.         while (index > 0) {
  36.             cur = cur.next;
  37.             index--;
  38.         }
  39.         dummy.next = cur.next;
  40.         // 切断,否则会有环
  41.         cur.next = null;
  42.         end.next = head;
  43.         return dummy.next;
  44.     }
  45. }
复制代码
2.思绪

起首计算链表的总长度,然跋文录链表末尾元素,再通过计算,找到正数第length - k % length个位置,然后根据题意进行组装,不外要注意堵截一下,否则会有环
9.LRU 缓存

1.答案

  1. package com.sunxiansheng.arithmetic.day13;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. /**
  5. * Description: 146. LRU 缓存
  6. *
  7. * @Author sun
  8. * @Create 2025/1/19 10:55
  9. * @Version 1.0
  10. */
  11. public class LRUCache {
  12.     // 双向链表的节点
  13.     class DLinkedNode {
  14.         int key;
  15.         int value;
  16.         DLinkedNode prev;
  17.         DLinkedNode next;
  18.         public DLinkedNode() {}
  19.         public DLinkedNode(int key, int value) {
  20.             this.key = key;
  21.             this.value = value;
  22.         }
  23.     }
  24.     // 双向链表的头尾指针
  25.     DLinkedNode head, tail;
  26.     // map:key是key,value是双向链表的节点
  27.     private Map<Integer, DLinkedNode> map;
  28.     // 容量
  29.     private int capacity;
  30.     public LRUCache(int capacity) {
  31.         map = new HashMap<>();
  32.         this.capacity = capacity;
  33.         // 头结点和尾节点
  34.         head = new DLinkedNode();
  35.         tail = new DLinkedNode();
  36.         head.next = tail;
  37.         tail.prev = head;
  38.     }
  39.     // 获取元素
  40.     public int get(int key) {
  41.         // 从map中去获取key
  42.         DLinkedNode dLinkedNode = map.get(key);
  43.         if (dLinkedNode == null) {
  44.             return -1;
  45.         }
  46.         // 获取之后,将元素放到链表头部
  47.         moveToHead(dLinkedNode);
  48.         return dLinkedNode.value;
  49.     }
  50.     private void moveToHead(DLinkedNode dLinkedNode) {
  51.         // 首先需要在链表中删除这个元素
  52.         delete(dLinkedNode);
  53.         // 然后将元素插入到头部
  54.         insertToHead(dLinkedNode);
  55.     }
  56.     private void insertToHead(DLinkedNode dLinkedNode) {
  57.         dLinkedNode.next = head.next;
  58.         dLinkedNode.prev = head;
  59.         head.next.prev = dLinkedNode;
  60.         head.next = dLinkedNode;
  61.     }
  62.     private static void delete(DLinkedNode dLinkedNode) {
  63.         dLinkedNode.prev.next = dLinkedNode.next;
  64.         dLinkedNode.next.prev = dLinkedNode.prev;
  65.     }
  66.     // 插入或更新元素
  67.     public void put(int key, int value) {
  68.         // 先获取元素
  69.         DLinkedNode dLinkedNode = map.get(key);
  70.         // 如果元素有值了,就替换值,并移动到头部
  71.         if (dLinkedNode != null) {
  72.             dLinkedNode.value = value;
  73.             moveToHead(dLinkedNode);
  74.         } else {
  75.             // 没有值则需要新增元素
  76.             dLinkedNode = new DLinkedNode(key, value);
  77.             // 确保容量足够
  78.             ensureCapacity(map.size() + 1);
  79.             // 目前容量一定足够,直接插入到头部即可
  80.             map.put(key, dLinkedNode);
  81.             insertToHead(dLinkedNode);
  82.         }
  83.     }
  84.     private void ensureCapacity(int newSize) {
  85.         if (newSize <= capacity) {
  86.             return;
  87.         }
  88.         // 如果容量不够,则需要删除最后的一个元素
  89.         map.remove(tail.prev.key);
  90.         delete(tail.prev);
  91.     }
  92. }
复制代码
2.思绪

使用双向链表+map来做
起首需要一个双向链表的类,key,value,next,prev即为属性
然后需要三个参数,双向链表的前后指针,map,容量
10.两两交换链表中的节点

1.答案

  1. package com.sunxiansheng.arithmetic.day13;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 24. 两两交换链表中的节点
  5. *
  6. * @Author sun
  7. * @Create 2025/1/19 12:01
  8. * @Version 1.0
  9. */
  10. public class t24 {
  11.     public ListNode swapPairs(ListNode head) {
  12.         ListNode dummy = new ListNode(0);
  13.         dummy.next = head;
  14.         ListNode cur = dummy;
  15.         // 提前记录prev
  16.         ListNode prev = dummy;
  17.         // 循环翻转
  18.         while (true) {
  19.             // 先判断是否有一组
  20.             for (int i = 0; i < 2; i++) {
  21.                 if (cur.next == null) {
  22.                     return dummy.next;
  23.                 }
  24.                 cur = cur.next;
  25.             }
  26.             // 到这里就是有一组了,开始翻转
  27.             ListNode start = prev.next;
  28.             ListNode then = start.next;
  29.             reverse(prev, start, then);
  30.             // 更新prev和cur
  31.             prev = start;
  32.             cur = prev;
  33.         }
  34.     }
  35.     // 两个一组翻转链表
  36.     private void reverse(ListNode prev, ListNode start, ListNode then) {
  37.         start.next = then.next;
  38.         then.next = prev.next;
  39.         prev.next = then;
  40.         then = start.next;
  41.     }
  42. }
复制代码
2.思绪

就是两个一组翻转链表,翻转链表的次数是节点数减一,然后要提前记录prev,而且在翻转后更新prev和start
11.环形链表 II

1.答案

  1. package com.sunxiansheng.arithmetic.day13;
  2. import com.sunxiansheng.arithmetic.util.ListNode;
  3. /**
  4. * Description: 142. 环形链表 II
  5. *
  6. * @Author sun
  7. * @Create 2025/1/19 12:31
  8. * @Version 1.0
  9. */
  10. public class t142 {
  11.     public ListNode detectCycle(ListNode head) {
  12.         // 快慢指针
  13.         ListNode slow = head;
  14.         ListNode fast = head;
  15.         while (fast != null && fast.next != null) {
  16.             slow = slow.next;
  17.             fast = fast.next.next;
  18.             if (slow == fast) {
  19.                 // 这样只能代表有环,如果想要找到入环的第一个节点,就要让slow等于head,然后一起移动
  20.                 slow = head;
  21.                 while (slow != fast) {
  22.                     slow = slow.next;
  23.                     fast = fast.next;
  24.                 }
  25.                 return slow;
  26.             }
  27.         }
  28.         return null;
  29.     }
  30. }
复制代码
2.思绪

发现有环之后,如果想要找到入环的第一个节点,就要让slow便是head,然后一起移动,直到相遇

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

九天猎人

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表