当前位置:   article > 正文

数据结构与算法-链表练习题_int middle = (start +end )/2 ;if(start>=end)

int middle = (start +end )/2 ;if(start>=end)

leetcode的几道链表练习题:

  1. package com.freshbin.basics.linkedlist;
  2. /**
  3. * @author freshbin
  4. * @date 2020/5/2 14:54
  5. */
  6. public class ListNode {
  7. int val;
  8. ListNode next;
  9. ListNode(int x) {
  10. val = x;
  11. }
  12. }
  1. package com.freshbin.basics.linkedlist;
  2. import java.util.PriorityQueue;
  3. /**
  4. * 23. 合并K个排序链表
  5. *
  6. * 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
  7. * 示例:
  8. * 输入:
  9. * [
  10. *   1->4->5,
  11. *   1->3->4,
  12. *   2->6
  13. * ]
  14. * 输出: 1->1->2->3->4->4->5->6
  15. *
  16. * @author freshbin
  17. * @date 2020/5/3 14:37
  18. */
  19. public class Solution23 {
  20. /**
  21. * 思路:把k个链表的值都放入新数组,对新数组用归并排序或者快速排序,再把新数组的值存入链表
  22. *
  23. * @param lists
  24. * @return
  25. */
  26. public ListNode mergeKLists(ListNode[] lists) {
  27. if(lists == null || lists.length == 0) {
  28. return null;
  29. }
  30. // 获取总的数据量
  31. int numberSum = 0;
  32. for(ListNode listNode : lists) {
  33. while(listNode != null) {
  34. listNode = listNode.next;
  35. numberSum++;
  36. }
  37. }
  38. // new一个数组存入所有数据
  39. int[] newArray = new int[numberSum];
  40. int index = 0;
  41. for(ListNode listNode : lists) {
  42. while(listNode != null) {
  43. newArray[index++] = listNode.val;
  44. listNode = listNode.next;
  45. }
  46. }
  47. // 对数组排序
  48. // 归并排序
  49. // mergeSort(newArray, 0, numberSum-1);
  50. // 快速排序
  51. quickSort(newArray, 0, numberSum-1);
  52. // 将排序后的数组放入链表
  53. ListNode newNode = new ListNode(-1);
  54. ListNode currentNode = newNode;
  55. for(int val : newArray) {
  56. currentNode.next = new ListNode(val);
  57. currentNode = currentNode.next;
  58. }
  59. return newNode.next;
  60. }
  61. private void quickSort(int[] newArray, int start, int end) {
  62. if(start >= end) {
  63. return;
  64. }
  65. int targetIndex = partition(newArray, start, end);
  66. quickSort(newArray, start, targetIndex-1);
  67. quickSort(newArray, targetIndex+1, end);
  68. }
  69. private int partition(int[] newArray, int left, int right) {
  70. int targetVal = newArray[right];
  71. while(left < right) {
  72. while(newArray[left] <= targetVal && left < right) {
  73. left++;
  74. }
  75. newArray[right] = newArray[left];
  76. newArray[left] = targetVal;
  77. while(newArray[right] >= targetVal && right > left) {
  78. right--;
  79. }
  80. newArray[left] = newArray[right];
  81. newArray[right] = targetVal;
  82. }
  83. return left;
  84. }
  85. private void mergeSort(int[] newArray, int start, int end) {
  86. if(start >= end) {
  87. return;
  88. }
  89. int middle = (start + end) / 2;
  90. mergeSort(newArray, start, middle);
  91. mergeSort(newArray, middle+1, end);
  92. mergeArray(newArray, start, middle, end);
  93. }
  94. /**
  95. * 合并左右两个数组
  96. * @param newArray
  97. * @param start
  98. * @param middle
  99. * @param end
  100. */
  101. private void mergeArray(int[] newArray, int start, int middle, int end) {
  102. int left = start, right = middle + 1, k = 0;
  103. int[] tempArr = new int[end-start+1];
  104. while(left <= middle && right <= end) {
  105. if(newArray[left] <= newArray[right]) {
  106. tempArr[k++] = newArray[left++];
  107. } else {
  108. tempArr[k++] = newArray[right++];
  109. }
  110. }
  111. while(left <= middle) {
  112. tempArr[k++] = newArray[left++];
  113. }
  114. while(right <= end) {
  115. tempArr[k++] = newArray[right++];
  116. }
  117. int index = 0;
  118. for(int i = start; i <= end; i++) {
  119. newArray[i] = tempArr[index++];
  120. }
  121. }
  122. /**
  123. * 将k个链表头放入小跟堆中,然后再从中把堆顶元素依次取出来,每取一次,都把当前链表的下一个节点放入堆中
  124. * 测试发现,放堆中的运行时间还真不如 直接把链表数据都放到数组,再对数组排序后扔回链表,
  125. * @param lists
  126. * @return
  127. */
  128. public ListNode mergeKListsByHeap(ListNode[] lists) {
  129. if(lists == null || lists.length == 0) {
  130. return null;
  131. }
  132. // 将k个链表的表头放入优先级队列,即小根堆
  133. PriorityQueue<ListNode> queue = new PriorityQueue<>((l1, l2) -> l1.val - l2.val);
  134. for(ListNode listNode : lists) {
  135. if(listNode != null) {
  136. queue.add(listNode);
  137. }
  138. }
  139. ListNode head = new ListNode(-1);
  140. ListNode currentNode = head;
  141. // 依次取出队列元素,即取出堆顶元素
  142. while(!queue.isEmpty()) {
  143. currentNode.next = queue.poll();
  144. currentNode = currentNode.next;
  145. if(currentNode.next != null) {
  146. // 将该链表的下一节点放入队列,即放入堆中
  147. queue.add(currentNode.next);
  148. }
  149. }
  150. return head.next;
  151. }
  152. }
  1. package com.freshbin.basics.linkedlist;
  2. import java.util.HashSet;
  3. /**
  4. * 141. 环形链表
  5. * 给定一个链表,判断链表中是否有环。
  6. * 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。
  7. * 如果 pos 是 -1,则在该链表中没有环。
  8. * 示例 1:
  9. * 输入:head = [3,2,0,-4], pos = 1
  10. * 输出:true
  11. * 解释:链表中有一个环,其尾部连接到第二个节点。
  12. *
  13. * @author freshbin
  14. * @date 2020/5/3 14:37
  15. */
  16. public class Solution141 {
  17. /**
  18. * 思路:遍历链表,用散列表保存遍历过的值
  19. * 当链表值与散列表值一致,说明出现环,退出
  20. *
  21. * @param head
  22. * @return
  23. */
  24. public boolean hasCycle(ListNode head) {
  25. HashSet hashSet = new HashSet();
  26. while(head != null) {
  27. if(hashSet.contains(head)) {
  28. return true;
  29. }
  30. hashSet.add(head);
  31. head = head.next;
  32. }
  33. return false;
  34. }
  35. /**
  36. * 快慢指针法,当快指针与慢指针相等,说明有环
  37. * @param head
  38. * @return
  39. */
  40. public boolean hasCycle01(ListNode head) {
  41. if(head == null) {
  42. return false;
  43. }
  44. ListNode slowNode = head;
  45. ListNode fastNode = head.next;
  46. if(slowNode == fastNode) {
  47. return true;
  48. }
  49. while(fastNode != null && fastNode.next != null) {
  50. if(slowNode == fastNode) {
  51. return true;
  52. }
  53. slowNode = slowNode.next;
  54. fastNode = fastNode.next.next;
  55. }
  56. return false;
  57. }
  58. }
  1. package com.freshbin.basics.linkedlist;
  2. /**
  3. * 876. 链表的中间结点
  4. *
  5. * 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
  6. * 如果有两个中间结点,则返回第二个中间结点。
  7. *
  8. * @author freshbin
  9. * @date 2020/5/3 14:21
  10. */
  11. public class Solution876 {
  12. /**
  13. * 思路:用两个指针遍历链表,快指针每次都两步,慢指针每次走一步,
  14. * 如果快指针下一节点或者下下一节点为空,那么就说明快指针走到尽头了
  15. * 这时候慢指针的下一指针就是中间节点
  16. *
  17. * @param head
  18. * @return
  19. */
  20. public ListNode middleNode(ListNode head) {
  21. if(head == null || head.next == null) {
  22. return head;
  23. }
  24. if(head.next.next == null) {
  25. return head.next;
  26. }
  27. ListNode slowNode = head;
  28. ListNode fastNode = head.next;
  29. while(fastNode.next != null && fastNode.next.next != null) {
  30. fastNode = fastNode.next.next;
  31. slowNode = slowNode.next;
  32. }
  33. // 慢指针的下一节点就是中间节点
  34. return slowNode.next;
  35. }
  36. public static void main(String[] arg) {
  37. ListNode listNode = new ListNode(1);
  38. listNode.next = new ListNode(2);
  39. listNode.next.next = new ListNode(3);
  40. listNode.next.next.next = new ListNode(4);
  41. Solution876 solution876 = new Solution876();
  42. System.out.println(solution876.middleNode(listNode).val);
  43. }
  44. }
  1. package com.freshbin.basics.linkedlist;
  2. /**
  3. * 面试题 02.03. 删除中间节点
  4. *
  5. * 实现一种算法,删除单向链表中间的某个节点(除了第一个和最后一个节点,不一定是中间节点),假定你只能访问该节点。
  6. *
  7. * 示例:
  8. * 输入:单向链表a->b->c->d->e->f中的节点c
  9. * 结果:不返回任何数据,但该链表变为a->b->d->e->f
  10. *
  11. * @author freshbin
  12. * @date 2020/5/3 11:16
  13. */
  14. public class Solution1462 {
  15. /**
  16. * 思路:用两个指针遍历链表,快指针每次都两步,慢指针每次走一步,
  17. * 如果快指针下一节点或者下下一节点为空,那么就说明快指针走到尽头了
  18. * 这时候慢指针的下一指针中间节点
  19. *
  20. * 提交之后发现,神他妈删除中间节点,这踏马入参原来是要删除的节点,
  21. * 那踏马这不是删除当前节点吗?
  22. *
  23. * 将后面节点的值赋到当前节点,然后把当前节点指针指向后节点的下一节点即可
  24. *
  25. * @param node
  26. */
  27. public void deleteNode(ListNode node) {
  28. /*if(node == null || node.next == null || node.next.next == null) {
  29. return;
  30. }
  31. ListNode slowNode = node;
  32. ListNode fastNode = node.next;
  33. while(fastNode.next != null && fastNode.next.next != null) {
  34. slowNode = slowNode.next;
  35. fastNode = fastNode.next.next;
  36. }
  37. // 删除中间节点
  38. slowNode.next = slowNode.next.next;*/
  39. node.val = node.next.val;
  40. node.next = node.next.next;
  41. }
  42. public static void main(String[] arg) {
  43. ListNode listNode = new ListNode(1);
  44. listNode.next = new ListNode(2);
  45. listNode.next.next = new ListNode(3);
  46. listNode.next.next.next = new ListNode(4);
  47. Solution1462 solution1462 = new Solution1462();
  48. solution1462.deleteNode(listNode.next.next);
  49. while(listNode != null) {
  50. System.out.print(listNode.val + "->");
  51. listNode = listNode.next;
  52. }
  53. }
  54. }
  1. package com.freshbin.basics.linkedlist;
  2. /**
  3. * 面试题18. 删除链表的节点
  4. * 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
  5. * 返回删除后的链表的头节点。
  6. *
  7. * 示例 1:
  8. * 输入: head = [4,5,1,9], val = 5
  9. * 输出: [4,1,9]
  10. * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
  11. *
  12. * 示例 2:
  13. * 输入: head = [4,5,1,9], val = 1
  14. * 输出: [4,5,9]
  15. * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
  16. *
  17. * @author freshbin
  18. * @date 2020/5/2 15:43
  19. */
  20. public class Solution1568 {
  21. /**
  22. * 思路:遍历链表,如果当前节点的下一节点值与目标值一致,那么将当前节点的指针指向该节点的下下一节点
  23. * @param head
  24. * @param val
  25. * @return
  26. */
  27. public ListNode deleteNode(ListNode head, int val) {
  28. ListNode currentNode = head;
  29. if(currentNode == null) {
  30. return null;
  31. }
  32. if(currentNode.val == val) {
  33. return currentNode.next;
  34. }
  35. while(currentNode.next != null) {
  36. if(currentNode.next.val == val) {
  37. currentNode.next = currentNode.next.next;
  38. }
  39. currentNode = currentNode.next;
  40. }
  41. return head;
  42. }
  43. }
  1. package com.freshbin.basics.linkedlist;
  2. /**
  3. * 面试题24. 反转链表
  4. *
  5. * 定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
  6. *
  7. * 示例:
  8. * 输入: 1->2->3->4->5->NULL
  9. * 输出: 5->4->3->2->1->NULL
  10. *
  11. * @author freshbin
  12. * @date 2020/5/2 14:53
  13. */
  14. public class Solution1573 {
  15. /**
  16. * 思路:遍历链表,用一个辅助链表将当前链表对象放入辅助链表
  17. * 辅助链表当前对象的next指针指向上一个对象, 同时将链表与辅助链表指针都一直往后移动
  18. *
  19. * @param head
  20. * @return
  21. */
  22. public ListNode reverseList(ListNode head) {
  23. if(head == null) {
  24. return null;
  25. }
  26. ListNode listNode = new ListNode(head.val);
  27. ListNode currentNode = head.next;
  28. while(currentNode != null) {
  29. ListNode next = currentNode.next;
  30. ListNode preNode = listNode;
  31. currentNode.next = preNode;
  32. listNode = currentNode;
  33. currentNode = next;
  34. }
  35. return listNode;
  36. }
  37. public static void main(String[] arg) {
  38. Solution1573 solution1573 = new Solution1573();
  39. ListNode listNode = new ListNode(1);
  40. listNode.next = new ListNode(2);
  41. listNode.next.next = new ListNode(3);
  42. solution1573.reverseList(listNode);
  43. }
  44. }

断断续续写了两三天,复习了快排和归并排序,没想到学过又忘记了。

快排:1、快排是先分成左右两个区,分区的节点不用再参与左边或者右边的分区,因为这个节点的左边数据都比该节点小,右边数据都比该节点大,所以这个节点是全局有序的,不用参与左右分区。

2、再对0到分区节点-1继续分区;

3、最后对分区节点+1到最后的索引分区;

归并排序:先分左右部分,再合并。

1、获取中间节点;

2、从左边开始节点到中间节点分左右部分;

3、从中间节点+1到右边最后节点分左右部分;

4、合并两个分区的数据。

链表的基本操作:链表反转,找中间节点,判断是否有环。

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

闽ICP备14008679号