package SecondBrush.LinkedList; /** * 83. 删除排序链表中的重复元素 * 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 * */ /** * 这个题目自己就直接做出来了,只是循环条件少写了一个 cur.next != null * 首先这道题目是 排序链表,所以相等的一定在一起,只需要对比 cur.val 和 cur.next.val * 如果相等直接跨过去, * 不相等就直接 移动 指向 * */ public class RemoveDuplicatesSortedList_83 { public ListNode deleteDuplicates(ListNode head) { ListNode cur = head; while (cur != null && cur.next != null){ if (cur.val == cur.next.val){ cur.next = cur.next.next; }else { cur = cur.next; } } return head; } }
package SecondBrush.LinkedList; /** * 82. 删除排序链表中的重复元素 II * 给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。 * 输入:head = [1,2,3,3,4,4,5] * 输出:[1,2,5] * */ /** * 想到的方法是双指针,因为这个可能设计到删除头结点,所以需要使用虚拟头结点 * 简单梳理思路:因为涉及到删除元素,所以需要虚拟头节点,双指针,一个指向虚拟节点(prev),一个指向 head(cur), * 因为要删除重复元素,且是有序的,所以重复元素都是在一起的,所以使用cur找到最后一个重复元素 * 如果pre.next 是cur,说明两个指针之间没有重复数据,否则 pre.next = cur.next * */ public class RemoveDuplicatesSortedListII_82 { public ListNode deleteDuplicates(ListNode head) { ListNode dummynode = new ListNode(-1,head); ListNode prev = dummynode; ListNode cur = head; while (cur!= null){ //如果出现重复的情况如下 //相等的结点则跳过,走到相同值元素的最后一步 while (cur.next!=null && cur.val == cur.next.val){ cur = cur.next; } //如果pre和cur之间没有重复节点,pre后移 if (prev.next == cur){ prev = prev.next; }else { prev.next = cur.next; } cur = cur.next; } return dummynode.next; } }
package SecondBrush.LinkedList; /** * 92. 反转链表 II * 给你单链表的头指针 head 和两个整数 left 和 right ,其中left <= right 。 * 请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。 * */ /** * 自己尝试写一下,将中间链表单独拿出来反转,之后,再进行拼接 * * * */ public class ReverseLinkedListII_92 { public ListNode reverseBetween(ListNode head, int left, int right) { // 设置 dummyNode 是这一类问题的一般做法 ListNode dummyNode = new ListNode(-1); dummyNode.next = head; ListNode pre = dummyNode; for (int i = 0; i < left - 1; i++) { pre = pre.next; } ListNode cur = pre.next; ListNode next; for (int i = 0; i < right - left; i++) { next = cur.next; cur.next = next.next; next.next = pre.next; pre.next = next; } return dummyNode.next; } }
package SecondBrush.LinkedList; /** * 876. 链表的中间结点 * 给你单链表的头结点 head ,请你找出并返回链表的中间结点。 * 如果有两个中间结点,则返回第二个中间结点。 * */ /** * 1.朴素解法:先遍历整个链表,得到长度,再取中间值,然后再遍历一半取目标值 * * 2.快慢指针:没想到这个,有点环形链表的意思 * */ public class MiddleLinkedList_876 { public ListNode middleNode(ListNode head) { ListNode p = head, q = head; while (q != null && q.next != null) { q = q.next.next; p = p.next; } return p; } }
package SecondBrush.LinkedList; /** * 剑指 Offer 22. 链表中倒数第k个节点 * 输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。 * 例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。 * */ /** * 1.朴素解法:想到的就是先遍历长度,然后减去 倒数长度,从前往后走 * 2.快慢指针:这个和之前的有一道题目很像, * */ public class GetKthFromEnd_22 { public ListNode getKthFromEnd(ListNode head, int k) { int len = 0; ListNode cur = head; while (cur != null){ cur = cur.next; len++; } cur = head; int cha = len - k; for (int i = 0; i < cha; i++) { cur = cur.next; } return cur.next; } public ListNode getKthFromEnd2(ListNode head, int k) { ListNode frontNode = head, behindNode = head; while (frontNode != null && k > 0) { frontNode = frontNode.next; k--; } while (frontNode != null) { frontNode = frontNode.next; behindNode = behindNode.next; } return behindNode; } }
package SecondBrush.LinkedList; /** * 234. 回文链表 * 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 * 回文链表指的是有对称性 * */ /** * 找到最后的节点,一个朝前遍历,一个朝后遍历,判断相遇前是否全部一致,如果不一致,说明不是回文链表 * -- 初始想法,但是写不出来,后指针不好往前遍历 * * 现在想起来快慢指针 * * */ public class PalindromeLinkedList_234 { public boolean isPalindrome(ListNode head) { // 要实现 O(n) 的时间复杂度和 O(1) 的空间复杂度,需要翻转后半部分 if (head == null || head.next == null) { return true; } ListNode fast = head; ListNode slow = head; // 根据快慢指针,找到中间节点或者前半部分链表的尾节点(注意判断条件) while(fast.next != null && fast.next.next != null) { fast = fast.next.next; slow = slow.next; } // 反转后半部分链表 slow = reverse(slow.next); while(slow != null) { if (head.val != slow.val) { return false; } head = head.next; slow = slow.next; } return true; } /** * 反转(迭代) */ private ListNode reverse(ListNode head){ ListNode pre = null; ListNode next = null; while(head != null) { next = head.next; head.next = pre; pre = head; head = next; } return pre; } }
package SecondBrush.LinkedList; /** * 21. 合并两个有序链表 * 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 * 输入:l1 = [1,2,4], l2 = [1,3,4] * 输出:[1,1,2,3,4,4] * */ /** * 思路:初始想法,定义两个指向,分别指向两个链表的头结点,然后谁小,就排在前面 * * */ public class MergeTwoSortedLists_21 { public ListNode mergeTwoLists(ListNode list1, ListNode list2) { // 类似归并排序中的合并过程 ListNode dummyHead = new ListNode(0); ListNode cur = dummyHead; while (list1 != null && list2 != null) { if (list1.val < list2.val) { cur.next = list1; cur = cur.next; list1 = list1.next; } else { cur.next = list2; cur = cur.next; list2 = list2.next; } } // 任一为空,直接连接另一条链表 if (list1 == null) { cur.next = list2; } else { cur.next = list1; } return dummyHead.next; } }
package SecondBrush.LinkedList; /** * 面试题 02.04. 分割链表 * 给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 * 你不需要保留每个分区中各节点的初始相对位置。 * 输入:head = [1,4,3,2,5,2], x = 3 * 输出:[1,2,2,4,3,5] * */ /** * 初始想法,首先要找到,第一个大于或等于x的节点,这个直接遍历即可-- * * 想的不太对 * */ public class PartitionListLCCI_0204 { public ListNode partition(ListNode head, int x) { ListNode small = new ListNode(0); ListNode smallHead = small; ListNode large = new ListNode(0); ListNode largeHead = large; while (head != null) { if (head.val < x) { small.next = head; small = small.next; } else { large.next = head; large = large.next; } head = head.next; } large.next = null; small.next = largeHead.next; return smallHead.next; } }
package SecondBrush.LinkedList; /** * 141. 环形链表 *给你一个链表的头节点 head ,判断链表中是否有环。 * 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 * 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 * 注意:pos 不作为参数进行传递。仅仅是为了标识链表的实际情况。 * 如果链表中存在环,则返回 true 。 否则,返回 false 。 * */ public class LinkedListCycle_141 { public boolean hasCycle(ListNode head) { ListNode fast = head; ListNode slow = head; while (fast != null && fast.next != null){ fast = fast.next.next; slow = slow.next; if (fast == slow){ return true; } } return false; } }
package SecondBrush.LinkedList; /** * 剑指 Offer 06. 从尾到头打印链表 * 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 */ public class PrintLinkedList_offer06 { public int[] reversePrint(ListNode head) { ListNode cur = head; int count = 0; while (cur != null) { count++; cur = cur.next; } int[] nums = new int[count]; cur = head; for (int i = count - 1; i >= 0; i--) { nums[i] = cur.val; cur = cur.next; } return nums; } }
package SecondBrush.LinkedList; /** * 剑指 Offer 35. 复杂链表的复制 * 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点, * 还有一个 random 指针指向链表中的任意节点或者 null。 * */ public class CopyRandomList_offer35 { public Node copyRandomList(Node head) { if (head == null) { return head; } //将拷贝节点放到原节点后面,例如1->2->3这样的链表就变成了这样1->1'->2->2'->3->3' for (Node node = head, copy = null; node != null; node = node.next.next) { copy = new Node(node.val); copy.next = node.next; node.next = copy; } //把拷贝节点的random指针安排上 for (Node node = head; node != null; node = node.next.next) { if (node.random != null) { node.next.random = node.random.next; } } //分离拷贝节点和原节点,变成1->2->3和1'->2'->3'两个链表,后者就是答案 Node newHead = head.next; for (Node node = head, temp = null; node != null && node.next != null;) { temp = node.next; node.next = temp.next; node = temp; } return newHead; } }
标签:head,题目,cur,补充,next,链表,ListNode,null From: https://www.cnblogs.com/lipinbigdata/p/17537086.html