Tips:
1.链表结构dummy node 的使用。当链表结构发生变化时使用dummy node.也就是其链表表头可能发生变化的时候。
2.链表结构基本操作:
插入一个节点
删除一个节点
旋转链表
合并两个链表
求一个链表的中间位置
几个总结:
以下题目细节容易出错:
1. 删除排序链表重复元素这两个题,两个循环的使用。
2. 翻转链表,删除倒数第n个结点这两个题,首先找倒数第n,不够跳出,然后两指针移动的这两个题目。
删除排序链表中的重复元素****
给定一个排序链表,删除所有重复的元素每个元素只留下一个
1 public ListNode deleteDuplicates(ListNode head) { 2 ListNode cur = head; 3 while (cur != null) { 4 while (cur.next != null && cur.val == cur.next.val) { 5 cur.next = cur.next.next; 6 } 7 cur = cur.next; 8 } 9 return head; 10 }
删除排序链表中的重复数字 II
给定一个排序链表,删除所有重复的元素只留下原链表中没有重复的元素。
题目不难,但是有需要注意细节。引入dummyNode prev 和 curt简化代码
1 public ListNode deleteDuplicates(ListNode head) { 2 if (head == null || head.next == null) { 3 return head; 4 } 5 ListNode dummy = new ListNode(0); 6 dummy.next = head; 7 ListNode tail = dummy; 8 while (head != null) { 9 while (head != null && head.next != null && head.val == head.next.val) { 10 head = head.next; 11 } 12 if (tail.next == head) { 13 tail = tail.next; 14 head = head.next; 15 } else { 16 tail.next = head.next; 17 head = head.next; 18 } 19 } 20 return dummy.next; 21 }
在O(1)时间复杂度删除链表节点
给定一个单链表中的一个等待被删除的节点(非表头或表尾)。请在在O(1)时间复杂度删除该链表节点。
没多少意思,就是套路。
1 public void deleteNode(ListNode node) { 2 // write your code here 3 if (node == null || node.next == null) { 4 return; 5 } 6 node.val = node.next.val; 7 node.next = node.next.next; 8 }
删除链表中的元素
删除链表中等于给定值val
的所有节点
1 public ListNode removeElements(ListNode head, int val) { 2 // Write your code here 3 if (head == null) { 4 return null; 5 } 6 ListNode dummy = new ListNode(0); 7 dummy.next = head; 8 ListNode prev = dummy; 9 ListNode curt = head; 10 while (curt != null) { 11 while (curt != null && curt.val == val) { 12 curt = curt.next; 13 } 14 prev.next = curt; 15 prev = curt; 16 if (curt != null) { 17 curt = curt.next; 18 } 19 } 20 return dummy.next; 21 }
无序链表的重复项删除
删除链表中等于给定值val
的所有节点
1 public ListNode removeElements(ListNode head, int val) { 2 // Write your code here 3 if (head == null) { 4 return null; 5 } 6 ListNode dummy = new ListNode(0); 7 dummy.next = head; 8 ListNode prev = dummy; 9 ListNode curt = head; 10 while (curt != null) { 11 while (curt != null && curt.val == val) { 12 curt = curt.next; 13 } 14 prev.next = curt; 15 prev = curt; 16 if (curt != null) { 17 curt = curt.next; 18 } 19 } 20 return dummy.next; 21 }
两两交换链表中的节点
1 public ListNode swapPairs(ListNode head) { 2 // Write your code here 3 if (head == null || head.next == null) { 4 return head; 5 } 6 ListNode dummy = new ListNode(0); 7 dummy.next = head; 8 ListNode tail = dummy; 9 ListNode tmp = null; 10 while (head != null && head.next != null) { 11 tmp = head.next.next; 12 tail.next = head.next; 13 head.next.next = head; 14 head.next = tmp; 15 tail = head; 16 head = tmp; 17 } 18 return dummy.next; 19 }
交换链表当中两个节点
给你一个链表以及两个权值v1
和v2
,交换链表中权值为v1
和v2
的这两个节点。保证链表中节点权值各不相同,如果没有找到对应节点,那么什么也不用做。
1 public ListNode swapNodes(ListNode head, int v1, int v2) { 2 // Write your code here 3 ListNode dummy = new ListNode(0); 4 dummy.next = head; 5 ListNode curt = head; 6 ListNode first = null; 7 ListNode prevFirst = null; 8 ListNode nextFirst = null; 9 ListNode second = null; 10 ListNode prevSecond = null; 11 ListNode nextSecond = null; 12 ListNode prev = dummy; 13 while (curt != null) { 14 if (v1 == curt.val) { 15 first = curt; 16 prevFirst = prev; 17 nextFirst = curt.next; 18 } 19 else if (v2 == curt.val) { 20 second = curt; 21 prevSecond = prev; 22 nextSecond = curt.next; 23 } 24 prev = curt; 25 curt = curt.next; 26 } 27 if (first != null && second != null) { 28 if (prevFirst == second) { 29 prevSecond.next = first; 30 first.next = second; 31 second.next = nextFirst; 32 } 33 else if (prevSecond == first) { 34 prevFirst.next = second; 35 second.next = first; 36 first.next = nextSecond; 37 } 38 else { 39 prevFirst.next = second; 40 second.next = nextFirst; 41 prevSecond.next = first; 42 first.next = nextSecond; 43 } 44 return dummy.next; 45 } 46 else { 47 return head; 48 } 49 }
删除链表中倒数第n个节点
给定一个链表,删除链表中倒数第n个节点,返回链表的头节点。
旋转链表 --not bug free
给定一个链表,旋转链表,使得每个节点向右移动k个位置,其中k是一个非负数
之前提交的代码其实是有bug的,lintcode测试不完备。
方法一:两个指针
1 public ListNode rotateRight(ListNode head, int k) { 2 if (head == null || k == 0) { 3 return head; 4 } 5 ListNode dummy = new ListNode(0); 6 dummy.next = head; 7 ListNode right = dummy; 8 ListNode left = dummy; 9 int i = 0; 10 for (; i < k; i++) { 11 right = right.next; // 不能与下一句话交换顺序,否则跳出时i记录的就不是结点个数 12 if (right == null) { 13 break; 14 } 15 16 } 17 if (right == null) { 18 k %= i; 19 if (k == 0) { 20 return head; 21 } 22 right = dummy; 23 for (i = 0; i < k; i++) { 24 right = right.next; 25 } 26 } 27 while (right.next != null) { 28 right = right.next; 29 left = left.next; 30 } 31 ListNode newHead = left.next; 32 left.next = null; 33 right.next = dummy.next; 34 return newHead; 35 }
方法二:直接先求出长度,省的出现那么多问题
1 public ListNode rotateRight(ListNode head, int k) { 2 if (head == null || k == 0) { 3 return head; 4 } 5 int size = 0; 6 ListNode cur = head; 7 while (cur.next != null) { 8 size++; 9 cur = cur.next; 10 } 11 ListNode tail = cur; 12 size += 1; 13 k %= size; 14 if (k == 0) { 15 return head; 16 } 17 size = size - k - 1; 18 cur = head; 19 for (int i = 0; i < size; i++) { 20 cur = cur.next; 21 } 22 ListNode newHead = cur.next; 23 cur.next = null; 24 tail.next = head; 25 return newHead; 26 }
翻转链表
翻转一个链表
1 public ListNode reverse(ListNode head) { 2 // write your code here 3 if (head == null || head.next == null) { 4 return head; 5 } 6 ListNode curt = head; 7 ListNode prev = null; 8 ListNode tmp; 9 while (curt != null) { 10 tmp = curt.next; 11 curt.next = prev; 12 prev = curt; 13 curt = tmp; 14 } 15 return prev; 16 }
翻转链表 II
翻转链表中第m个节点到第n个节点的部分
分步骤进行,先找到节点,再翻转,再连接。
1 public ListNode reverseBetween(ListNode head, int m , int n) { 2 // write your code 3 if (head == null || head.next == null) { 4 return head; 5 } 6 ListNode dummy = new ListNode(0); 7 dummy.next = head; 8 reverseNode(dummy, m, n); 9 return dummy.next; 10 } 11 public void reverseNode(ListNode dummy, int m, int n) { 12 ListNode head = dummy.next; 13 ListNode begin = findKth(head, m - 1); 14 ListNode curt = begin == null ? head:begin.next; 15 ListNode end = curt; 16 //reverse 17 ListNode tmp = null; 18 ListNode prev = null; 19 for (int i = m; i <= n; i++) { 20 tmp = curt.next; 21 curt.next = prev; 22 prev = curt; 23 curt = tmp; 24 } 25 //connect 26 if (begin == null) { 27 dummy.next = prev; 28 } 29 else { 30 begin.next = prev; 31 } 32 end.next = curt; 33 } 34 public ListNode findKth(ListNode head, int k) { 35 if (k == 0) { 36 return null; 37 } 38 while (k > 1 && head != null) { 39 head = head.next; 40 k--; 41 } 42 return head; 43 }
链表划分
给定一个单链表和数值x,划分链表使得所有小于x的节点排在大于等于x的节点之前。
你应该保留两部分内链表节点原有的相对顺序。
代码中Attention,注意!容易忽略
public ListNode partition(ListNode head, int x) { // write your code here if (head == null || head.next == null) { return head; } ListNode leftDummy = new ListNode(0); ListNode rightDummy = new ListNode(0); ListNode left = leftDummy; ListNode right = rightDummy; while (head != null) { if (head.val < x) { left.next = head; left = head; } else { right.next = head; right = head; } head = head.next; } right.next = null;//attention left.next = rightDummy.next; return leftDummy.next; }
链表排序
数组:
merge Sort : time O(nlogn) space O(n)
quick Sort: time O(nlogn) space O(1)
heap Sort: time O(nlogn) apace O(1)
链表排序不能使用堆排序,因为堆排序是直接定位去找元素的,在链表结构中,这较浪费时间。
这里使用归并排序
public ListNode sortList(ListNode head) { // write your code here if (head == null || head.next == null) { return head; } ListNode middle = middleNode(head); ListNode right = sortList(middle.next); middle.next = null; ListNode left = sortList(head); return merge(left, right); } public ListNode merge(ListNode left, ListNode right) { ListNode dummy = new ListNode(0); ListNode tail = dummy; while (left != null && right != null) { if (left.val < right.val) { tail.next = left; left = left.next; } else { tail.next = right; right = right.next; } tail = tail.next; } if (left != null) { tail.next = left; } else { tail.next = right; } return dummy.next; } public ListNode middleNode(ListNode head) { if (head == null || head.next == null) { return head; } ListNode fast = head.next; ListNode slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; } return slow; }
链表插入排序*
有一点需要特别注意的,dummy.next并没有指向head,前面排序好的部分的尾节点指向空,这样就避免了12345这样的考察当前,发现并没有比它大的所带来的问题。
1 public ListNode insertionSortList(ListNode head) { 2 // write your code here 3 ListNode dummy = new ListNode(0); 4 while (head != null) { 5 ListNode node = dummy; 6 while (node.next != null && node.next.val < head.val) { 7 node = node.next; 8 } 9 ListNode tmp = head.next; 10 head.next = node.next; 11 node.next = head; 12 head = tmp; 13 } 14 return dummy.next; 15 }
重排链表
给定一个单链表L: L0→L1→…→Ln-1→Ln,
重新排列后为:L0→Ln→L1→Ln-1→L2→Ln-2→…
必须在不改变节点值的情况下进行原地操作。
找中点 -> 求逆序->合并
1 public void reorderList(ListNode head) { 2 if (head == null || head.next == null) { 3 return; 4 } 5 ListNode middle = findMiddle(head); 6 ListNode newHead = reverseList(middle); 7 mergeTwoList(head, newHead); 8 } 9 public void mergeTwoList(ListNode head, ListNode newHead) { 10 while (newHead != null) { 11 ListNode temp1 = head.next; 12 ListNode temp2 = newHead.next; 13 head.next = newHead; 14 newHead.next = temp1; 15 head = temp1; 16 newHead = temp2; 17 } 18 if (head != null) { 19 // 如果原来节点个数为偶数个的话,前半部分的最后一个节点指针还指向后半部分的,如果不加此操作,导致MLE 20 head.next = null; // Attention! 21 } 22 } 23 public ListNode reverseList(ListNode head) { 24 ListNode prev = null; 25 while (head != null) { 26 ListNode temp = head.next; 27 head.next = prev; 28 prev = head; 29 head = temp; 30 } 31 return prev; 32 } 33 public ListNode findMiddle(ListNode head) { 34 ListNode right = head; 35 ListNode left = head; 36 while (right != null && right.next != null) { 37 right = right.next.next; 38 left = left.next; 39 } 40 return left; 41 }
Palindrome Linked List
Implement a function to check if a linked list is a palindrome.
找中点—>求逆序->比较
1 public boolean isPalindrome(ListNode head) { 2 // Write your code here 3 if (head == null || head.next == null) { 4 return true; 5 } 6 ListNode middle = findMiddle(head); 7 ListNode reverseHead = reverseList(middle.next); 8 middle.next = null; 9 return isPalindromeHelp(head, reverseHead); 10 } 11 public ListNode findMiddle (ListNode head) { 12 if (head == null || head.next == null) { 13 return head; 14 } 15 ListNode fast = head.next; 16 ListNode slow = head; 17 while (fast != null && fast.next != null) { 18 fast = fast.next.next; 19 slow = slow.next; 20 } 21 return slow; 22 } 23 public ListNode reverseList(ListNode head) { 24 ListNode prev = null; 25 while (head != null) { 26 ListNode temp = head.next; 27 head.next = prev; 28 prev = head; 29 head = temp; 30 } 31 return prev; 32 } 33 public boolean isPalindromeHelp(ListNode l1, ListNode l2) { 34 while (l1 != null && l2 != null) { 35 if (l1.val != l2.val) { 36 return false; 37 } 38 l1 = l1.next; 39 l2 = l2.next; 40 } 41 return true; 42 }
带环链表
给定一个链表,判断它是否有环。
1 public boolean hasCycle(ListNode head) { 2 // write your code here 3 ListNode fast = head; 4 ListNode slow = head; 5 while (fast != null && fast.next != null) { 6 fast = fast.next.next; 7 slow = slow.next; 8 if (slow == fast) { 9 return true; 10 } 11 } 12 return false; 13 }
带环链表 II
给定一个链表,如果链表中存在环,则返回到链表中环的起始节点的值,如果没有环,返回null。
1 public ListNode detectCycle(ListNode head) { 2 // write your code here 3 ListNode fast = head; 4 ListNode slow = head; 5 while (fast != null && fast.next != null) { 6 fast = fast.next.next; 7 slow = slow.next; 8 if (fast == slow) { 9 break; 10 } 11 } 12 if (fast == null || fast.next == null) {//Attention 13 return null; 14 } 15 slow = head; 16 while (fast != slow) { 17 fast = fast.next; 18 slow = slow.next; 19 } 20 return slow; 21 }
合并两个排序链表
1 public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 2 // write your code here 3 ListNode dummy = new ListNode(0); 4 ListNode tail = dummy; 5 while (l1 != null && l2 != null) { 6 if (l1.val < l2.val) { 7 tail.next = l1; 8 l1 = l1.next; 9 } 10 else { 11 tail.next = l2; 12 l2 = l2.next; 13 } 14 tail = tail.next; 15 } 16 if (l1 != null) { 17 tail.next = l1; 18 } 19 else { 20 tail.next = l2; 21 } 22 return dummy.next; 23 }
合并k个排序链表
合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。
方法一:分治 Nlogk
1 public ListNode mergeKLists(List<ListNode> lists) { 2 // write your code here 3 if (lists == null || lists.size() == 0) { 4 return null; 5 } 6 return mergeKListsHelp(lists, 0, lists.size() - 1); 7 } 8 public ListNode mergeKListsHelp(List<ListNode> lists, int start, int end) { 9 if (start == end) { 10 return lists.get(start); 11 } 12 if (start + 1 == end) { 13 return mergeTwoLists(lists.get(start), lists.get(end)); 14 } 15 int mid = (start + end) / 2; 16 return mergeTwoLists(mergeKListsHelp(lists, start,mid), mergeKListsHelp(lists, mid + 1, end)); 17 } 18 public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 19 // write your code here 20 ListNode dummy = new ListNode(0); 21 ListNode tail = dummy; 22 while (l1 != null && l2 != null) { 23 if (l1.val < l2.val) { 24 tail.next = l1; 25 l1 = l1.next; 26 } 27 else { 28 tail.next = l2; 29 l2 = l2.next; 30 } 31 tail = tail.next; 32 } 33 if (l1 != null) { 34 tail.next = l1; 35 } 36 else { 37 tail.next = l2; 38 } 39 return dummy.next; 40 }
方法二:heap Nlogk
private Comparator<ListNode> ListNodeComparator = new Comparator<ListNode>(){ public int compare(ListNode left, ListNode right) { if (left == null) { return 1; } if (right == null) { return -1; } return left.val - right.val; } }; public ListNode mergeKLists(List<ListNode> lists) { // write your code here if (lists == null || lists.size() == 0) { return null; } Queue<ListNode> queue = new PriorityQueue<ListNode>(lists.size(), ListNodeComparator); for (int i = 0; i < lists.size(); i++) { if (lists.get(i) != null) { queue.offer(lists.get(i)); } } ListNode dummy = new ListNode(0); ListNode tail = dummy; while (!queue.isEmpty()) { ListNode top = queue.poll(); tail.next = top; tail = top; if (top.next != null) { queue.offer(top.next); } } return dummy.next; }
方法三:merge Two By Two
1 public ListNode mergeKLists(List<ListNode> lists) { 2 // write your code here 3 if (lists == null || lists.size() == 0) { 4 return null; 5 } 6 while (lists.size() > 1) { 7 List<ListNode> new_List = new ArrayList<ListNode>(); 8 for (int i = 0; i < lists.size() - 1; i += 2) { 9 ListNode tmp = mergeTwoList(lists.get(i),lists.get(i + 1)); 10 new_List.add(tmp); 11 } 12 if (lists.size() % 2 == 1) { 13 new_List.add(lists.get(lists.size() - 1)); 14 } 15 lists = new_List; 16 } 17 return lists.get(0); 18 } 19 public ListNode mergeTwoList(ListNode l1, ListNode l2) { 20 ListNode dummy = new ListNode(0); 21 ListNode tail = dummy; 22 while (l1 != null && l2 != null) { 23 if (l1.val < l2.val) { 24 tail.next = l1; 25 l1 = l1.next; 26 } 27 else { 28 tail.next = l2; 29 l2 = l2.next; 30 } 31 tail = tail.next; 32 } 33 if (l1 != null) { 34 tail.next = l1; 35 } 36 else { 37 tail.next = l2; 38 } 39 return dummy.next; 40 }
复制带随机指针的链表
给出一个链表,每个节点包含一个额外增加的随机指针可以指向链表中的任何节点或空的节点。
返回一个深拷贝的链表。
方法一:hashMap
1 public RandomListNode copyRandomList(RandomListNode head) { 2 // write your code here 3 if (head == null) { 4 return null; 5 } 6 HashMap<RandomListNode, RandomListNode> hashMap = new HashMap<>(); 7 RandomListNode tmpNode = null; 8 RandomListNode old = head; 9 while (old != null) { 10 tmpNode = new RandomListNode(old.label); 11 hashMap.put(old, tmpNode); 12 old = old.next; 13 } 14 old = head; 15 while (old != null) { 16 RandomListNode new_node = hashMap.get(old); 17 new_node.next = hashMap.get(old.next); 18 new_node.random = hashMap.get(old.random); 19 old = old.next; 20 } 21 return hashMap.get(head); 22 }
方法二:指针操作,先和在一起。然后再分开。复制next 复制random 拆开
public RandomListNode copyRandomList(RandomListNode head) { // write your code here if (head == null) { return null; } copyNext(head); copyRandom(head); return splitList(head); } public void copyNext(RandomListNode head) { while (head != null) { RandomListNode new_node = new RandomListNode(head.label); new_node.next = head.next; new_node.random = head.random; head.next = new_node; head = new_node.next; } } public void copyRandom(RandomListNode head) { while (head != null) { if (head.next.random != null) { head.next.random = head.random.next; } head = head.next.next; } } public RandomListNode splitList(RandomListNode head) { RandomListNode new_head = head.next; while (head != null) { RandomListNode tmp = head.next; head.next = tmp.next; head = head.next; if (tmp.next != null) { tmp.next = tmp.next.next; } } return new_head; }
排序列表转换为二分查找树
分治
1 public TreeNode sortedListToBST(ListNode head) { 2 // write your code here 3 if (head == null) { 4 return null; 5 } 6 if (head.next == null) { 7 return new TreeNode(head.val); 8 } 9 ListNode preMiddle = findPreMiddle(head); 10 if (preMiddle == null) { 11 TreeNode root = new TreeNode(head.val); 12 TreeNode right = new TreeNode(head.next.val); 13 root.right = right; 14 return root; 15 } 16 ListNode middle = preMiddle.next; 17 TreeNode root = new TreeNode(middle.val); 18 19 TreeNode right = sortedListToBST(middle.next); 20 preMiddle.next = null; 21 TreeNode left = sortedListToBST(head); 22 23 root.left = left; 24 root.right = right; 25 return root; 26 } 27 public ListNode findPreMiddle(ListNode head) { 28 if (head == null || head.next == null) { 29 return head; 30 } 31 ListNode prev = null; 32 ListNode slow = head; 33 ListNode fast = head.next; 34 while (fast != null && fast.next != null) { 35 fast = fast.next.next; 36 prev = slow; 37 slow = slow.next; 38 } 39 return prev; 40 }
分治法二:
1 private ListNode current; 2 public TreeNode sortedListToBST(ListNode head) { 3 // write your code here 4 if (head == null) { 5 return null; 6 } 7 int size = getSize(head); 8 current = head; 9 return sortedListToBSTHelper(size); 10 } 11 public int getSize(ListNode head) { 12 int size = 0; 13 while (head != null) { 14 head = head.next; 15 size++; 16 } 17 return size; 18 } 19 public TreeNode sortedListToBSTHelper(int size) { 20 if (size <= 0) { 21 return null; 22 } 23 TreeNode left = sortedListToBSTHelper(size / 2); 24 TreeNode root = new TreeNode(current.val); 25 current = current.next; 26 TreeNode right = sortedListToBSTHelper(size - 1 -size / 2); 27 root.left = left; 28 root.right = right; 29 return root; 30 }
将二叉查找树转换成双链表
将一个二叉查找树按照中序遍历转换成双向链表。
方法一:
中序遍历结束后再进行转化。
1 public DoublyListNode bstToDoublyList(TreeNode root) { 2 // Write your code here 3 if (root == null) { 4 return null; 5 } 6 List<DoublyListNode> list = new ArrayList<>(); 7 inorderTraverse(list, root); 8 int size = list.size(); 9 for (int i = 1; i < size - 1; i++) { 10 list.get(i).next = list.get(i + 1); 11 list.get(i).prev = list.get(i - 1); 12 } 13 if (size > 1) { 14 list.get(0).next = list.get(1); 15 list.get(size - 1).prev = list.get(size - 2); 16 } 17 else { 18 list.get(0).next = null; 19 } 20 return list.get(0); 21 } 22 public void inorderTraverse(List<DoublyListNode> list, TreeNode root) { 23 if (root.left != null) { 24 inorderTraverse(list, root.left); 25 } 26 list.add(new DoublyListNode(root.val)); 27 if (root.right != null) { 28 inorderTraverse(list, root.right); 29 } 30 31 }
方法二:ResultType,记录最左边最右边
public DoublyListNode bstToDoublyList(TreeNode root) { // Write your code here if (root == null) { return null; } return helper(root).first; } public ResultType helper(TreeNode root) { if (root == null) { return null; } ResultType left = helper(root.left); ResultType right = helper(root.right); DoublyListNode node = new DoublyListNode(root.val); ResultType result = new ResultType(null,null); if (left == null) { result.first = node; } else { result.first = left.first; left.last.next = node; node.prev =left.last; } if (right == null) { result.last = node; } else { result.last = right.last; node.next = right.first; right.first.prev = node; } return result; }
K组翻转链表
给你一个链表以及一个k,将这个链表从头指针开始每k个翻转一下。
链表元素个数不是k的倍数,最后剩余的不用翻转。
一段一段翻转。首先获取长度,看一共有多少段需要翻转。对每一段需要翻转的,记录tail 和head,翻转结果返回尾部和下一个节点。然后tail.next = 尾部,head.next = 下一个,
tail = head,head = head.next。
1 public ListNode reverseKGroup(ListNode head, int k) { 2 // Write your code here 3 if (head == null || k <= 1) { 4 return head; 5 } 6 int size = getSize(head); 7 if (size < k) { 8 return head; 9 } 10 ListNode dummy = new ListNode(0); 11 dummy.next = head; 12 ListNode tail = dummy; 13 int group = size / k; 14 for (int i = 0; i < group; i++) { 15 ListNode[] reversed = reverseKHelp(head, k); 16 tail.next = reversed[0]; 17 head.next = reversed[1]; 18 tail = head; 19 head = head.next; 20 } 21 return dummy.next; 22 } 23 public ListNode[] reverseKHelp(ListNode head, int k) { 24 ListNode prev = null; 25 ListNode curt = head; 26 ListNode tmp; 27 while (curt != null && k > 0) { 28 tmp = curt.next; 29 curt.next = prev; 30 prev = curt; 31 curt = tmp; 32 k--; 33 } 34 ListNode[] res = {prev,curt}; 35 return res; 36 } 37 public int getSize(ListNode head) { 38 int size = 0; 39 while (head != null) { 40 head = head.next; 41 size++; 42 } 43 return size; 44 }
链表求和
你有两个用链表代表的整数,其中每个节点包含一个数字。数字存储按照在原来整数中相反
的顺序,使得第一个数字位于链表的开头。写出一个函数将两个整数相加,用链表形式返回和。
1 public ListNode addLists(ListNode l1, ListNode l2) { 2 // write your code here 3 if (l1 == null) { 4 return l2; 5 } 6 if (l2 == null) { 7 return l1; 8 } 9 ListNode dummy = new ListNode(0); 10 ListNode tail = dummy; 11 int flag = 0; 12 int sum = 0; 13 while (l1 != null && l2 != null) { 14 sum = l1.val + l2.val + flag; 15 flag = sum/10; 16 tail.next = new ListNode(sum % 10); 17 tail = tail.next; 18 l1 = l1.next; 19 l2 = l2.next; 20 } 21 while (l1 != null) { 22 sum = l1.val + flag; 23 flag = sum/10; 24 tail.next = new ListNode(sum % 10); 25 tail = tail.next; 26 l1 = l1.next; 27 } 28 while (l2 != null) { 29 sum = l2.val + flag; 30 flag = sum/10; 31 tail.next = new ListNode(sum % 10); 32 tail = tail.next; 33 l2 = l2.next; 34 } 35 if (flag == 0) { 36 tail.next = null; 37 } 38 else { 39 tail.next = new ListNode(1); 40 } 41 return dummy.next; 42 }
链表求和 II
假定用一个链表表示两个数,其中每个节点仅包含一个数字。假设这两个数的数字顺序
排列,请设计一种方法将两个数相加,并将其结果表现为链表的形式。
1 public ListNode addLists2(ListNode l1, ListNode l2) { 2 // write your code here 3 if (l1 == null) { 4 return l2; 5 } 6 if (l2 == null) { 7 return l1; 8 } 9 ListNode rl1 = reverseNode(l1); 10 ListNode rl2 = reverseNode(l2); 11 ListNode sumNode = addHelper(rl1, rl2); 12 return reverseNode(sumNode); 13 } 14 public ListNode reverseNode(ListNode head) { 15 ListNode prev = null; 16 while (head != null) { 17 ListNode tmp = head.next; 18 head.next = prev; 19 prev = head; 20 head = tmp; 21 } 22 return prev; 23 } 24 public ListNode addHelper(ListNode l1, ListNode l2) { 25 int flag =0; 26 ListNode dummy = new ListNode(0); 27 ListNode tail = dummy; 28 while (l1 != null && l2 != null) { 29 int sum = l1.val + l2.val + flag; 30 flag = sum / 10; 31 tail.next = new ListNode(sum % 10); 32 tail = tail.next; 33 l1 = l1.next; 34 l2 = l2.next; 35 } 36 while (l1 != null) { 37 int sum = l1.val + flag; 38 flag = sum / 10; 39 tail.next = new ListNode(sum % 10); 40 tail = tail.next; 41 l1 = l1.next; 42 } 43 while (l2 != null) { 44 int sum = l2.val + flag; 45 flag = sum / 10; 46 tail.next = new ListNode(sum % 10); 47 tail = tail.next; 48 l2 = l2.next; 49 } 50 if (flag != 0) { 51 tail.next = new ListNode(1); 52 } 53 return dummy.next; 54 }
链表倒数第n个节点
找到单链表倒数第n个节点,保证链表中节点的最少数量为n。
方法一:
1 找到单链表倒数第n个节点,保证链表中节点的最少数量为n。
方法二:
1 ListNode nthToLast(ListNode head, int n) { 2 // write your code here 3 if (head == null || head.next == null) { 4 return head; 5 } 6 ListNode curt = head; 7 for (int i = 0; i < n; i++) { 8 curt = curt.next; 9 } 10 ListNode res = head; 11 while (curt != null) { 12 curt = curt.next; 13 res = res.next; 14 } 15 return res; 16 }