赞
踩
leetcode的几道链表练习题:
- package com.freshbin.basics.linkedlist;
-
- /**
- * @author freshbin
- * @date 2020/5/2 14:54
- */
- public class ListNode {
- int val;
- ListNode next;
-
- ListNode(int x) {
- val = x;
- }
- }
- package com.freshbin.basics.linkedlist;
-
- import java.util.PriorityQueue;
-
- /**
- * 23. 合并K个排序链表
- *
- * 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
- * 示例:
- * 输入:
- * [
- * 1->4->5,
- * 1->3->4,
- * 2->6
- * ]
- * 输出: 1->1->2->3->4->4->5->6
- *
- * @author freshbin
- * @date 2020/5/3 14:37
- */
- public class Solution23 {
- /**
- * 思路:把k个链表的值都放入新数组,对新数组用归并排序或者快速排序,再把新数组的值存入链表
- *
- * @param lists
- * @return
- */
- public ListNode mergeKLists(ListNode[] lists) {
- if(lists == null || lists.length == 0) {
- return null;
- }
-
- // 获取总的数据量
- int numberSum = 0;
- for(ListNode listNode : lists) {
- while(listNode != null) {
- listNode = listNode.next;
- numberSum++;
- }
- }
- // new一个数组存入所有数据
- int[] newArray = new int[numberSum];
- int index = 0;
- for(ListNode listNode : lists) {
- while(listNode != null) {
- newArray[index++] = listNode.val;
- listNode = listNode.next;
- }
- }
-
- // 对数组排序
- // 归并排序
- // mergeSort(newArray, 0, numberSum-1);
- // 快速排序
- quickSort(newArray, 0, numberSum-1);
-
- // 将排序后的数组放入链表
- ListNode newNode = new ListNode(-1);
- ListNode currentNode = newNode;
- for(int val : newArray) {
- currentNode.next = new ListNode(val);
- currentNode = currentNode.next;
- }
-
- return newNode.next;
- }
-
- private void quickSort(int[] newArray, int start, int end) {
- if(start >= end) {
- return;
- }
-
- int targetIndex = partition(newArray, start, end);
- quickSort(newArray, start, targetIndex-1);
- quickSort(newArray, targetIndex+1, end);
- }
-
- private int partition(int[] newArray, int left, int right) {
- int targetVal = newArray[right];
- while(left < right) {
- while(newArray[left] <= targetVal && left < right) {
- left++;
- }
- newArray[right] = newArray[left];
- newArray[left] = targetVal;
- while(newArray[right] >= targetVal && right > left) {
- right--;
- }
- newArray[left] = newArray[right];
- newArray[right] = targetVal;
- }
-
- return left;
- }
-
- private void mergeSort(int[] newArray, int start, int end) {
- if(start >= end) {
- return;
- }
-
- int middle = (start + end) / 2;
- mergeSort(newArray, start, middle);
- mergeSort(newArray, middle+1, end);
- mergeArray(newArray, start, middle, end);
- }
-
- /**
- * 合并左右两个数组
- * @param newArray
- * @param start
- * @param middle
- * @param end
- */
- private void mergeArray(int[] newArray, int start, int middle, int end) {
- int left = start, right = middle + 1, k = 0;
- int[] tempArr = new int[end-start+1];
- while(left <= middle && right <= end) {
- if(newArray[left] <= newArray[right]) {
- tempArr[k++] = newArray[left++];
- } else {
- tempArr[k++] = newArray[right++];
- }
- }
-
- while(left <= middle) {
- tempArr[k++] = newArray[left++];
- }
-
- while(right <= end) {
- tempArr[k++] = newArray[right++];
- }
-
- int index = 0;
- for(int i = start; i <= end; i++) {
- newArray[i] = tempArr[index++];
- }
- }
-
- /**
- * 将k个链表头放入小跟堆中,然后再从中把堆顶元素依次取出来,每取一次,都把当前链表的下一个节点放入堆中
- * 测试发现,放堆中的运行时间还真不如 直接把链表数据都放到数组,再对数组排序后扔回链表,
- * @param lists
- * @return
- */
- public ListNode mergeKListsByHeap(ListNode[] lists) {
- if(lists == null || lists.length == 0) {
- return null;
- }
- // 将k个链表的表头放入优先级队列,即小根堆
- PriorityQueue<ListNode> queue = new PriorityQueue<>((l1, l2) -> l1.val - l2.val);
- for(ListNode listNode : lists) {
- if(listNode != null) {
- queue.add(listNode);
- }
- }
-
- ListNode head = new ListNode(-1);
- ListNode currentNode = head;
- // 依次取出队列元素,即取出堆顶元素
- while(!queue.isEmpty()) {
- currentNode.next = queue.poll();
- currentNode = currentNode.next;
- if(currentNode.next != null) {
- // 将该链表的下一节点放入队列,即放入堆中
- queue.add(currentNode.next);
- }
- }
-
- return head.next;
- }
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.freshbin.basics.linkedlist;
-
- import java.util.HashSet;
-
- /**
- * 141. 环形链表
- * 给定一个链表,判断链表中是否有环。
- * 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。
- * 如果 pos 是 -1,则在该链表中没有环。
- * 示例 1:
- * 输入:head = [3,2,0,-4], pos = 1
- * 输出:true
- * 解释:链表中有一个环,其尾部连接到第二个节点。
- *
- * @author freshbin
- * @date 2020/5/3 14:37
- */
- public class Solution141 {
-
- /**
- * 思路:遍历链表,用散列表保存遍历过的值
- * 当链表值与散列表值一致,说明出现环,退出
- *
- * @param head
- * @return
- */
- public boolean hasCycle(ListNode head) {
- HashSet hashSet = new HashSet();
- while(head != null) {
- if(hashSet.contains(head)) {
- return true;
- }
- hashSet.add(head);
- head = head.next;
- }
-
- return false;
- }
-
- /**
- * 快慢指针法,当快指针与慢指针相等,说明有环
- * @param head
- * @return
- */
- public boolean hasCycle01(ListNode head) {
- if(head == null) {
- return false;
- }
-
- ListNode slowNode = head;
- ListNode fastNode = head.next;
- if(slowNode == fastNode) {
- return true;
- }
- while(fastNode != null && fastNode.next != null) {
- if(slowNode == fastNode) {
- return true;
- }
- slowNode = slowNode.next;
- fastNode = fastNode.next.next;
- }
-
- return false;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.freshbin.basics.linkedlist;
-
- /**
- * 876. 链表的中间结点
- *
- * 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
- * 如果有两个中间结点,则返回第二个中间结点。
- *
- * @author freshbin
- * @date 2020/5/3 14:21
- */
- public class Solution876 {
- /**
- * 思路:用两个指针遍历链表,快指针每次都两步,慢指针每次走一步,
- * 如果快指针下一节点或者下下一节点为空,那么就说明快指针走到尽头了
- * 这时候慢指针的下一指针就是中间节点
- *
- * @param head
- * @return
- */
- public ListNode middleNode(ListNode head) {
- if(head == null || head.next == null) {
- return head;
- }
- if(head.next.next == null) {
- return head.next;
- }
- ListNode slowNode = head;
- ListNode fastNode = head.next;
-
- while(fastNode.next != null && fastNode.next.next != null) {
- fastNode = fastNode.next.next;
- slowNode = slowNode.next;
- }
-
- // 慢指针的下一节点就是中间节点
- return slowNode.next;
- }
-
- public static void main(String[] arg) {
- ListNode listNode = new ListNode(1);
- listNode.next = new ListNode(2);
- listNode.next.next = new ListNode(3);
- listNode.next.next.next = new ListNode(4);
-
- Solution876 solution876 = new Solution876();
- System.out.println(solution876.middleNode(listNode).val);
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.freshbin.basics.linkedlist;
-
- /**
- * 面试题 02.03. 删除中间节点
- *
- * 实现一种算法,删除单向链表中间的某个节点(除了第一个和最后一个节点,不一定是中间节点),假定你只能访问该节点。
- *
- * 示例:
- * 输入:单向链表a->b->c->d->e->f中的节点c
- * 结果:不返回任何数据,但该链表变为a->b->d->e->f
- *
- * @author freshbin
- * @date 2020/5/3 11:16
- */
- public class Solution1462 {
- /**
- * 思路:用两个指针遍历链表,快指针每次都两步,慢指针每次走一步,
- * 如果快指针下一节点或者下下一节点为空,那么就说明快指针走到尽头了
- * 这时候慢指针的下一指针中间节点
- *
- * 提交之后发现,神他妈删除中间节点,这踏马入参原来是要删除的节点,
- * 那踏马这不是删除当前节点吗?
- *
- * 将后面节点的值赋到当前节点,然后把当前节点指针指向后节点的下一节点即可
- *
- * @param node
- */
- public void deleteNode(ListNode node) {
- /*if(node == null || node.next == null || node.next.next == null) {
- return;
- }
- ListNode slowNode = node;
- ListNode fastNode = node.next;
- while(fastNode.next != null && fastNode.next.next != null) {
- slowNode = slowNode.next;
- fastNode = fastNode.next.next;
- }
- // 删除中间节点
- slowNode.next = slowNode.next.next;*/
-
- node.val = node.next.val;
- node.next = node.next.next;
- }
-
- public static void main(String[] arg) {
- ListNode listNode = new ListNode(1);
- listNode.next = new ListNode(2);
- listNode.next.next = new ListNode(3);
- listNode.next.next.next = new ListNode(4);
-
- Solution1462 solution1462 = new Solution1462();
- solution1462.deleteNode(listNode.next.next);
-
- while(listNode != null) {
- System.out.print(listNode.val + "->");
- listNode = listNode.next;
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.freshbin.basics.linkedlist;
-
- /**
- * 面试题18. 删除链表的节点
- * 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
- * 返回删除后的链表的头节点。
- *
- * 示例 1:
- * 输入: head = [4,5,1,9], val = 5
- * 输出: [4,1,9]
- * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
- *
- * 示例 2:
- * 输入: head = [4,5,1,9], val = 1
- * 输出: [4,5,9]
- * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
- *
- * @author freshbin
- * @date 2020/5/2 15:43
- */
- public class Solution1568 {
- /**
- * 思路:遍历链表,如果当前节点的下一节点值与目标值一致,那么将当前节点的指针指向该节点的下下一节点
- * @param head
- * @param val
- * @return
- */
- public ListNode deleteNode(ListNode head, int val) {
- ListNode currentNode = head;
- if(currentNode == null) {
- return null;
- }
- if(currentNode.val == val) {
- return currentNode.next;
- }
- while(currentNode.next != null) {
- if(currentNode.next.val == val) {
- currentNode.next = currentNode.next.next;
- }
- currentNode = currentNode.next;
- }
- return head;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- package com.freshbin.basics.linkedlist;
-
- /**
- * 面试题24. 反转链表
- *
- * 定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
- *
- * 示例:
- * 输入: 1->2->3->4->5->NULL
- * 输出: 5->4->3->2->1->NULL
- *
- * @author freshbin
- * @date 2020/5/2 14:53
- */
- public class Solution1573 {
- /**
- * 思路:遍历链表,用一个辅助链表将当前链表对象放入辅助链表
- * 辅助链表当前对象的next指针指向上一个对象, 同时将链表与辅助链表指针都一直往后移动
- *
- * @param head
- * @return
- */
- public ListNode reverseList(ListNode head) {
- if(head == null) {
- return null;
- }
- ListNode listNode = new ListNode(head.val);
- ListNode currentNode = head.next;
- while(currentNode != null) {
- ListNode next = currentNode.next;
- ListNode preNode = listNode;
- currentNode.next = preNode;
- listNode = currentNode;
- currentNode = next;
- }
- return listNode;
- }
-
- public static void main(String[] arg) {
- Solution1573 solution1573 = new Solution1573();
- ListNode listNode = new ListNode(1);
- listNode.next = new ListNode(2);
- listNode.next.next = new ListNode(3);
- solution1573.reverseList(listNode);
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
断断续续写了两三天,复习了快排和归并排序,没想到学过又忘记了。
快排:1、快排是先分成左右两个区,分区的节点不用再参与左边或者右边的分区,因为这个节点的左边数据都比该节点小,右边数据都比该节点大,所以这个节点是全局有序的,不用参与左右分区。
2、再对0到分区节点-1继续分区;
3、最后对分区节点+1到最后的索引分区;
归并排序:先分左右部分,再合并。
1、获取中间节点;
2、从左边开始节点到中间节点分左右部分;
3、从中间节点+1到右边最后节点分左右部分;
4、合并两个分区的数据。
链表的基本操作:链表反转,找中间节点,判断是否有环。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。