当前位置:   article > 正文

LeetCode刷题 --- 链表_head: optional[listnode]

head: optional[listnode]

定义一个node节点

  1. class ListNode {
  2. int val;
  3. ListNode next;
  4. ListNode() {
  5. }
  6. ListNode(int val) {
  7. this.val = val;
  8. }
  9. ListNode(int val, ListNode next) {
  10. this.val = val;
  11. this.next = next;
  12. }
  13. }
  1. class ListNode:
  2. def __init__(self, val=0, next=None):
  3. self.val = val
  4. self.next = next

206 反转链表

题目:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

解题:

1、如果head为空或者只有一个节点,那么直接返回结果即可

2、否则,定义一个新链表,遍历旧链表,将每个节点插入到新链表的头部即可。

  1. public ListNode reverseList(ListNode head) {
  2. if (head == null || head.next == null) {
  3. return head;
  4. }
  5. ListNode res = new ListNode(head.val);
  6. while (head.next != null) {
  7. ListNode next = head.next;
  8. head = next;
  9. res = new ListNode(next.val, res);
  10. }
  11. return res;
  12. }
  1. def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
  2. if not head or not head.next:
  3. return head
  4. res = ListNode(head.val)
  5. while head.next:
  6. next_node = head.next
  7. head = next_node
  8. res = ListNode(next_node.val, res)
  9. return res

203 根据值来删除节点

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

定义一个头节点,和两个指针, p和q,如图,循环该链表:

1、如果q指针的值不等于目标值,则分别向后移动一位

2、如果q指针的值等于目标值,则p不懂,q后移,但是p仍指向q

  1. public List1Node removeElements(List1Node head, int val) {
  2. // 定义哨兵和双指针
  3. List1Node myHead = new List1Node(-1, head);
  4. List1Node p = myHead;
  5. List1Node q = p.next;
  6. while (q!=null) {
  7. if (q.val == val) {
  8. // 右指针等于目标值,q右移,p不变,但是p还指向q
  9. q = q.next;
  10. p.next = q;
  11. } else {
  12. // 两个指针均向后移动一位
  13. p = p.next;
  14. q = q.next;
  15. }
  16. }
  17. return myHead.next;
  18. }
  1. def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
  2. res = ListNode(-1, head)
  3. p = res
  4. q = head
  5. while q:
  6. if q.val == val:
  7. q = q.next
  8. p.next = q
  9. else:
  10. q = q.next
  11. p = p.next
  12. return res.next

19 删除链表的倒数第N个节点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

 解题1:

1、先获取链表的长度

2、找到倒数第N个节点的前一个节点,指向下一个节点即可

  1. class Solution {
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. int length = length(head);
  4. ListNode dummy = new ListNode(0,head);
  5. ListNode cur = dummy;
  6. for (int i = 1; i < length -n +1; i++) {
  7. cur = cur.next;
  8. }
  9. cur.next = cur.next ==null ? null : cur.next.next;
  10. return dummy.next;
  11. }
  12. public int length(ListNode head) {
  13. if (head == null) {
  14. return 0;
  15. }
  16. ListNode p = head;
  17. int count = 1;
  18. while (p.next != null) {
  19. p = p.next;
  20. count++;
  21. }
  22. return count;
  23. }
  24. }

解题2

定义两个指针节点p和q,分别指向头节点,先让q节点向后移动n步,然后,在让p和q同时后移,当q指向空的时候,p恰好是倒数第n个节点的前一个节点。

  1. class Solution {
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. ListNode dummy = new ListNode(0, head);
  4. ListNode p1 = dummy;
  5. ListNode p2 = dummy;
  6. for (int i = 0; i < n + 1; i++) {
  7. p2 = p2.next;
  8. }
  9. while (p2 != null) {
  10. p1 = p1.next;
  11. p2 = p2.next;
  12. }
  13. p1.next = p1.next.next;
  14. return dummy.next;
  15. }
  16. }
  1. def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
  2. p = q = res = ListNode(next=head)
  3. for i in range(n):
  4. p = p.next
  5. while p.next:
  6. q = q.next
  7. p = p.next
  8. q.next = q.next.next
  9. return res.next

83、 有序链表去重 (留下一个)

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 

解题1:

去重,可以使用Map或者set ,遍历链表,如果节点的值已经在集合中存在,那么这个节点就是重复节点,可以删除,如果不存在,则将值存入集合,继续遍历。

  1. class Solution {
  2. public ListNode deleteDuplicates(ListNode head) {
  3. if (head==null){
  4. return head;
  5. }
  6. Set<Integer> set = new HashSet<>();
  7. ListNode node = head;
  8. set.add(node.val);
  9. while (node.next!=null) {
  10. ListNode next = node.next;
  11. if (set.contains(next.val)){
  12. node.next = next.next;
  13. }else {
  14. node = next;
  15. set.add(next.val);
  16. }
  17. }
  18. return head;
  19. }
  20. }

 解题2:

定义哨兵节点,和两个指针节点p/q,比较p/q的值是否相等,如果相等,q后移,p还是指向q,如果不相等,同时后移。

  1. public ListNode deleteDuplicates(ListNode head) {
  2. if (head == null || head.next == null) {
  3. return head;
  4. }
  5. ListNode dummy = new ListNode(-101, head);
  6. ListNode p = dummy;
  7. ListNode q = dummy.next;
  8. while (q != null) {
  9. if (q.val == p.val) {
  10. q = q.next;
  11. p.next = q;
  12. } else {
  13. q = q.next;
  14. p = p.next;
  15. }
  16. }
  17. return dummy.next;
  18. }
  1. def deleteDuplicates1(self, head: Optional[ListNode]) -> Optional[ListNode]:
  2. if not head or not head.next:
  3. return head
  4. cur = head
  5. while cur.next:
  6. if cur.val == cur.next.val:
  7. cur.next = cur.next.next
  8. else:
  9. cur = cur.next
  10. return head

82. 删除排序链表中的重复元素 (重复的一个不留)

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

 解题:

参考上一题,定义哨兵节点,以及三个指针节点,仍然按照p和q比较,遍历,多定义的r节点,是p节点的上一个节点,pq相同的时候,q不断后移,一直移到为null或者值不同,然后将r的下一个节点指向q

  1. public ListNode deleteDuplicates(ListNode head) {
  2. if (head == null || head.next == null) {
  3. return head;
  4. }
  5. ListNode dummy = new ListNode(-200, head);
  6. ListNode r = dummy;
  7. ListNode p;
  8. ListNode q;
  9. while ((p = r.next) != null && (q = p.next) != null) {
  10. if (p.val == q.val) {
  11. while (q != null && q.val == p.val) {
  12. q = q.next;
  13. }
  14. r.next=q;
  15. } else {
  16. r = r.next;
  17. }
  18. }
  19. return dummy.next;
  20. }
  1. def deleteDuplicates3(self, head: Optional[ListNode]) -> Optional[ListNode]:
  2. if not head or not head.next:
  3. return head
  4. cur = dummy = ListNode(val=-200, next=head)
  5. while cur.next and cur.next.next:
  6. val = cur.next.val
  7. if cur.next.next.val == val:
  8. while cur.next and cur.next.val == val:
  9. cur.next = cur.next.next
  10. else:
  11. cur = cur.next
  12. return dummy

21 合并有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

解题:

定义一个新的头节点,遍历两个链表,哪个值小,就放在新建的头节点后面。如果有一个链表为null,那就把另外一个链表的值全放在新建链表的后面。

  1. public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
  2. // 头节点,及指针节点
  3. ListNode head = new ListNode();
  4. ListNode node = head;
  5. while (list1 != null && list2 != null) {
  6. if (list1.val <= list2.val) {
  7. node.next = list1;
  8. list1 = list1.next;
  9. } else {
  10. node.next = list2;
  11. list2 = list2.next;
  12. }
  13. node = node.next;
  14. }
  15. if (list1 != null) {
  16. node.next = list1;
  17. }
  18. if (list2 != null) {
  19. node.next = list2;
  20. }
  21. return head.next;
  22. }
  1. def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
  2. res = head = ListNode(-100001)
  3. while list1 and list2:
  4. if list1.val <= list2.val:
  5. head.next = list1
  6. list1 = list1.next
  7. else:
  8. head.next = list2
  9. list2 = list2.next
  10. head = head.next
  11. head.next = list1 if list1 else list2
  12. return res.next

23、和并多个升序链表

题解:参考21题,遍历链表,两两合并

  1. class Solution {
  2. public ListNode mergeKLists(ListNode[] lists) {
  3. ListNode node = null;
  4. for (int i = 0; i < lists.length; i++) {
  5. node = mergeTwoLists(lists[i], node);
  6. }
  7. return node;
  8. }
  9. public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
  10. // 头节点,及指针节点
  11. ListNode head = new ListNode();
  12. ListNode node = head;
  13. while (list1 != null && list2 != null) {
  14. if (list1.val <= list2.val) {
  15. node.next = list1;
  16. list1 = list1.next;
  17. } else {
  18. node.next = list2;
  19. list2 = list2.next;
  20. }
  21. node = node.next;
  22. }
  23. if (list1 != null) {
  24. node.next = list1;
  25. }
  26. if (list2 != null) {
  27. node.next = list2;
  28. }
  29. return head.next;
  30. }
  31. }

876. 链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

 

题解:

快慢指针法,定义两个指针,初始分别指向头节点,p每次前进一步,q每次前进两步,当q前进时为null了,此时p指向的就是题目要求的中间节点。

  1. public ListNode middleNode(ListNode head) {
  2. ListNode p1 = head;
  3. ListNode p2 = head;
  4. while (p2 != null && p2.next != null) {
  5. p1 = p1.next;
  6. p2 = p2.next.next;
  7. }
  8. return p1;
  9. }
  1. def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
  2. p = q = head
  3. while q and q.next:
  4. p = p.next
  5. q = q.next.next
  6. return p

243 回文链表

判断一个链表是不是回文链表,就是正读反读是一样的。

题解:

将给定的链表反转,然后将新链表和老链表逐个比较,一致则为true,否则为false。

  1. public boolean isPalindrome(ListNode head) {
  2. ListNode reverse = reverse(head);
  3. while (head != null) {
  4. if (head.val != reverse.val) {
  5. return false;
  6. }
  7. head = head.next;
  8. reverse = reverse.next;
  9. }
  10. return true;
  11. }
  12. public ListNode reverse(ListNode head) {
  13. if (head == null || head.next == null) {
  14. return head;
  15. }
  16. ListNode res = new ListNode(head.val);
  17. while (head.next != null) {
  18. ListNode next = head.next;
  19. head = next;
  20. res = new ListNode(next.val, res);
  21. }
  22. return res;
  23. }
  1. # 反转链表,然后一个个的比较
  2. def isPalindrome(self, head: Optional[ListNode]) -> bool:
  3. list = self.reverseList(head)
  4. while list:
  5. if list.val != head.val:
  6. return False
  7. else:
  8. list = list.next
  9. head = head.next
  10. return True
  11. # 数据放在数组中,然后反转数组,看val是否相等
  12. def isPalindrome1(self, head: Optional[ListNode]) -> bool:
  13. next_node = head
  14. val = []
  15. while next_node:
  16. val.append(next_node.val)
  17. next_node = next_node.next
  18. return val == val[::-1]

链表判环算法:

用快慢指针的方法(龟兔赛跑算法):

  1. 阶段1
    1. 龟一次走一步,兔子一次走两步
    2. 兔子能走到终点,那么就不存在环
    3. 兔子能追上龟(再次相遇),说明存在环。
  2. 阶段2
    1. 再次相遇时,兔子留在原地不动,龟退回到起点
    2. 兔子和龟都每次走一步
    3. 再次相遇的时候,相遇点就是环的入口。

解释一下阶段2:

  • 假设起点到环入口是a步,环一圈是b步
  • 从起点开始,走a+b*n都可以到环的入口
  • 第一次相遇:
    • 兔走了a + m*b +k 步,k是距离环入口的距离
    • 龟走了a + n*b +k 步,k是距离环入口的距离, m>n
    • 兔子走的路程是龟的两倍,所以 龟 = 兔 - 龟 = x*n 圈,龟走的是圈的整数倍
  • 因为走a+b*n都可以到环的入口,因此,从相遇点开始,在走a步,就可以找到环的入口。
  • 这个还有一个小bug,就是如果a=0,那么起点就是环入口。

141、判断是否是环形链表

根据上述判环算法,可以直接写出代码

  1. public boolean hasCycle(ListNode head) {
  2. ListNode p = head;
  3. ListNode q = head;
  4. while (q != null && q.next != null) {
  5. p = p.next;
  6. q = q.next.next;
  7. if (q == p) {
  8. return true;
  9. }
  10. }
  11. return false;
  12. }
  1. def hasCycle(self, head: Optional[ListNode]) -> bool:
  2. p1 = p2 = head
  3. while p1 and p2 and p2.next:
  4. p1 = p1.next
  5. p2 = p2.next.next
  6. if p1 == p2:
  7. return True
  8. return False

142 找到环形链表的入口

根据上述算法,可以直接在141的基础上改写代码

  1. public ListNode detectCycle(ListNode head) {
  2. ListNode p = head;
  3. ListNode q = head;
  4. while (q != null && q.next != null) {
  5. p = p.next;
  6. q = q.next.next;
  7. if (q == p) {
  8. // 判断里面改写代码,将p重新指向头节点,然后两个节点每次分别走一步
  9. p = head;
  10. while (true) {
  11. // 进到循环之后,先判断两个节点是否相等,
  12. // 解决了头结点就是入口节点的问题。
  13. if (q == p) {
  14. return q;
  15. }
  16. p = p.next;
  17. q = q.next;
  18. }
  19. }
  20. }
  21. return null;
  22. }
  1. def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
  2. p1 = p2 = head
  3. while p1 and p2 and p2.next:
  4. p1 = p1.next
  5. p2 = p2.next.next
  6. if p1 == p2:
  7. p1 = head
  8. while True:
  9. if p1 == p2:
  10. return p1
  11. p1 = p1.next
  12. p2 = p2.next
  13. return None

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

闽ICP备14008679号