从尾到头打印链表
翻转链表
翻转链表II
链表划分
合并两个排序链表
合并k个排序链表
链表求和
带环链表
找出带环链表的环入口
从尾到头打印链表
输入一个链表,从尾到头打印链表每个节点的值。
public class Solution { // 递归实现 ArrayList<Integer> result = new ArrayList<>(); public ArrayList<Integer> printListFromTailToHead(ListNode listNode){ if(listNode != null){ this.printListFromTailToHead(listNode.next); result.add(listNode.val); } return result; } // 借用stack public ArrayList<Integer> printListFromTailToHead3(ListNode listNode) { Stack<Integer> stack = new Stack<>(); ArrayList<Integer> list = new ArrayList<>(); while(listNode!=null){ stack.push(listNode.val); listNode = listNode.next; } while(!stack.isEmpty()){ list.add(stack.pop()); } return list; } }
翻转链表
// 从头到尾遍历原链表,每遍历一个节点,将其摘下放在新链表的最前段, O(n) public ListNode reverse(ListNode head) { ListNode prev = null; ListNode cur = head; while (cur != null) { ListNode temp = cur; // 保存当前要处理的节点 cur = cur.next; // 跳到下一个节点 temp.next = prev; prev = temp; } return prev; } // 递归 public ListNode reverse2(ListNode head) { if (head == null || head.next == null) { return head; } ListNode reHead = reverse2(head.next); head.next.next = head; head.next = null; return reHead; }
翻转链表II
翻转链表中第m个节点到第n个节点的部分。(给出链表1->2->3->4->5->null, m = 2 和n = 4,返回1->4->3->2->5->null )
分析:对于m、n,确定要翻转2->3->4。先找到2的前一个节点,prev;按照普通翻转链表的做法,翻转n-m次;最后,node[m].next=node[n].next,prev.next=node[n]
public ListNode reverseBetween(ListNode head, int m , int n) { if(head==null || head.next==null || m==n){ return head; } ListNode pre; ListNode dummy = new ListNode(0); pre = dummy; dummy.next = head; for(int i=0; i<m-1; i++){ pre = pre.next; } ListNode cur = pre.next, p = pre.next, node = null; for(int i=0; i<=n-m; i++){ ListNode nxt = cur.next; cur.next =node; node=cur; cur = nxt; } p.next = cur; pre.next = node; return dummy.next; }
链表划分
给定一个单链表和数值x,划分链表使得所有小于x的节点排在大于等于x的节点之前。 保留两部分内链表节点原有的相对顺序。
( 链表 1->4->3->2->5->2->null,并且 x=3 返回 1->2->2->4->3->5->null )
public ListNode partition(ListNode head, int x) { ListNode leftDummy = new ListNode(0); ListNode rightDummy = new ListNode(0); ListNode left = leftDummy, right = rightDummy; // 两个指针,left保存小于x的节点,right保存大于x的节点,最后left.next=rightDummy.next while (head != null) { if (head.val < x) { left.next = head; left = head; } else { right.next = head; right = head; } head = head.next; } right.next = null; left.next = rightDummy.next; return leftDummy.next; }
合并两个排序链表
将两个排序链表合并为一个新的排序链表
(给出 1->3->8->11->15->null
,2->null
, 返回 1->2->3->8->11->15->null
。)
public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0); ListNode lastNode = dummy; while(l1!=null && l2!=null){ if(l1.val<l2.val){ lastNode.next = l1; l1 = l1.next; }else{ lastNode.next = l2; l2 = l2.next; } lastNode = lastNode.next; } if(l1!=null){ lastNode.next = l1; }else{ lastNode.next = l2; } return dummy.next; }
合并k个排序链表
public ListNode mergeKLists(ListNode[] lists) { if(lists==null || lists.length==0) return null; mergeKLists(lists, 0, lists.length-1); return lists[0]; } public void mergeKLists(ListNode[] lists, int left, int right){ if(left>=right) return; int mid = left + (right+1-left)/2; mergeKLists(lists, left, mid-1); mergeKLists(lists, mid, right); ListNode dummy = new ListNode(0); merge2Lists(lists[left], lists[mid], dummy); lists[left] = dummy.next; } public void merge2Lists(ListNode l1, ListNode l2, ListNode dummy){ if(l1==null && l2==null){ return; } if(l1==null || (l2!=null && l2.val< l1.val)){ dummy.next = l2; merge2Lists(l1, l2.next, dummy.next); }else if(l2==null || (l1!=null && l1.val<= l2.val)){ dummy.next = l1; merge2Lists(l1.next, l2, dummy.next); } }
链表求和
两个用链表代表的整数,其中每个节点包含一个数字。数字存储按照在原来整数中相反
的顺序,使得第一个数字位于链表的开头。写出一个函数将两个整数相加,用链表形式返回和。
( 给出两个链表(2 -> 4 -> 3) + (5 -> 6 -> 4),返回7 -> 0 -> 8
)
public ListNode addLists(ListNode l1, ListNode l2) { if(l1 == null && l2 == null) { return null; } ListNode head = new ListNode(0); ListNode point = head; int carry = 0; // 进位 while(l1 != null && l2!=null){ int sum = carry + l1.val + l2.val; point.next = new ListNode(sum % 10); //本位上的数 carry = sum / 10; // 进位 l1 = l1.next; l2 = l2.next; point = point.next; } while(l1 != null) { int sum = carry + l1.val; point.next = new ListNode(sum % 10); carry = sum /10; l1 = l1.next; point = point.next; } while(l2 != null) { int sum = carry + l2.val; point.next = new ListNode(sum % 10); carry = sum /10; l2 = l2.next; point = point.next; } if (carry != 0) { point.next = new ListNode(carry); } return head.next; }
带环链表
判断链表是否有环
public boolean hasCycle(ListNode head) { if(head==null || head.next==null){ return false; } ListNode slow = head; ListNode fast = head; while(fast!=null && fast.next!=null){ slow = slow.next; fast = fast.next.next; if(slow == fast){ return true; } } return false; }
找出带环链表的环入口
给定一个链表,如果链表中存在环,则返回到链表中环的起始节点的值,如果没有环,返回null。
public ListNode detectCycle(ListNode head) { if(head==null || head.next==null || head.next.next==null) return null; ListNode pointer1 = head.next; ListNode pointer2 = head.next.next; //Step 1 while(pointer1!=pointer2){ if(pointer2.next==null || pointer2.next.next==null) return null; pointer1 = pointer1.next; pointer2 = pointer2.next.next; } pointer1 = head; //Step 2 p1从head开始,p2从交汇处开始,二者同时到达的位置就是环入口 while(pointer1!=pointer2){ pointer1 = pointer1.next; pointer2 = pointer2.next; } return pointer1; }