链表常见问题
1. 两数相加问题
给定两个链表,分别表示两个非负整数。他们的数字逆序存储在链表中,且每个节点只存储一个数字,计算两个数的和,并且返回和的链表头指针。
如:输入:2->4->3 , 5->6->4, 输出:7->0->8.
分析:因为两个数都是逆序存储的,因此可以从头往后加,而且每个节点存储的都是个位数,因此相加不会超过18。模拟两个数按位相加的过程就可以了。用一个额外的变量记录当前位相加是否有进位。
注意:
- 当两个链表长度不相等时该怎么处理?
- 最后一位是否有进位?
/** * 该算法计算两个逆序放置的链表的和,返回和的头指针 * 如:输入:2->4->3 , 5->6->4, 输出:7->0->8. * @param l1 * @param l2 * @return */ public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode h = new ListNode(-1); ListNode res = h; int flag = 0; ListNode p = l1, q = l2; while( p != null && q != null) { int temp = p.val + q.val; if(flag == 1) temp++; flag = temp / 10; temp %= 10; ListNode node = new ListNode(temp); res.next = node; res = res.next; p = p.next; q = q.next; } while(p != null) { int temp = p.val; if(flag == 1) temp++; flag = temp / 10; temp %= 10; ListNode node = new ListNode(temp); res.next = node; res = res.next; p = p.next; } while(q != null) { int temp = q.val; if(flag == 1) temp++; flag = temp / 10; temp %= 10; ListNode node = new ListNode(temp); res.next = node; res = res.next; q = q.next; } if(flag == 1) { ListNode node = new ListNode(1); res.next = node; } return h.next; }
2. 链表部分翻转问题
给定一个链表,翻转该链表熊m到n的位置。要求直接翻转而非申请新空间。
如:给定1->2->3->4->5,m=2, n=4, 返回1->4->3->2->5。
假设给出的参数满足:1 <= m <= n <= 链表长度。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode reverseBetween(ListNode l, int m, int n) { if(l == null || l.next == null) return l; if(m == n) return l; ListNode l1 = new ListNode(-1); l1.next = l; int count = 0; ListNode head = l1; while(count + 1< m) { head = head.next; count++; } count++; ListNode t = head.next; ListNode p, q; while(count < n) { p = t.next; q = head.next; head.next = p; t.next = p.next; p.next = q; count++; } return l1.next; } }
3. 链表去重问题
1) 给定排序的链表,删除重复元素,只保留重复元素第一次出现的结点。
如:给定:2->3->3->4->7->7->8, 返回:2->3->4->7->8.
/** * 删除链表中所有重复的节点(重复的节点中保留一个) * @param l * @return */ public ListNode deleteDuplicates(ListNode l) { if(l == null || l.next == null) return l; ListNode p = l; while(p != null && p.next != null) { if(p.val == p.next.val) { ListNode q = p.next; p.next = q.next; q.next = null; } else p = p.next; } return l; }
2)给定排序的链表,若发现重复元素,则重复元素全部删除。
如:给定:2->3->3->4->7->7->8, 返回:2->4->8.
/** * 该算法删除所有重复的节点,只要有重复,则全部删除 * @param l * @return */ public ListNode deleteDuplicatesII(ListNode l) { if(l == null || l.next == null) return l; ListNode head = new ListNode(-1); head.next = l; ListNode p = head; int temp = -1; while(p != null && p.next != null) { temp = p.next.val; ListNode q = p.next; boolean flag = false; while(q != null && q.next != null) { if(q.next.val == temp) { flag = true; q = q.next; } else break; } if(flag == true) { p.next = q.next; q.next = null; } else p = q; } return head.next; }
4. 链表划分问题
给定一个链表和一个值x,将链表划分成两部分,使得划分后小于x的节点在前,大于等于x的节点在后。在这两部分中要保持原链表汇总出现的顺序。
如:给定链表1->4->3->2->5->2和x=3,返回1->2->2->4->3->5.
/** * 给定一个链表和一个值x,将链表划分成两部分,使得划分后小于x的节点在前,大于等于x的节点在后。在这两部分中要保持原链表汇总出现的顺序。 * @param head * @param x * @return */ public ListNode partition(ListNode head, int x) { if(head == null || head.next == null) return head; ListNode head1 = new ListNode(-1); ListNode head2 = new ListNode(-1); ListNode h1 = head1, h2 = head2; ListNode p = head, q; while(p != null && p.next != null) { q = p.next; if(p.val < x) { h1.next = p; p.next = null; p = q; h1 = h1.next; } else { h2.next = p; p.next = null; p = q; h2 = h2.next; } } // System.out.println(p.val); if(p.val < x) { h1.next = p; h1 = h1.next; } else { h2.next = p; h2 = h2.next; } h1.next = head2.next; return head1.next; }
5. 单链公共节点问题
给定两个单向链表,计算两个链表的第一个公共节点,若没有公共节点,则返回空。
分析:因为是单链表,所以如果两个链表中有公共结点,只要相遇了就不会分开。以短的链表的长度为基准。
/** * 给定两个单向链表,计算两个链表的第一个公共节点,若没有公共节点,则返回空。 * @param head1 * @param head2 * @return */ public ListNode getIntersectionNode(ListNode head1, ListNode head2) { int len1 = 0, len2 = 0; ListNode p1 = head1, p2 = head2; while(p1 != null) { p1 = p1.next; len1++; } while(p2 != null) { p2 = p2.next; len2++; } ListNode q1 = (len1 > len2) ? head1 : head2; int count = 0; while(count < Math.abs(len1 - len2)) { q1 = q1.next; count++; } ListNode q2 = (len1 <= len2) ? head1 : head2; while(q1 != null && q2 != null) { if(q1 == q2) return q1; else { q1 = q1.next; q2 = q2.next; } } return null; }