链表
链表在面试中手写代码的几率很大,也是十分重要的一种数据结构,本身并不复杂,但通过各种形式的题型可以看出一个人思路的严谨性。
找出两个链表的交点
160. Intersection of Two Linked Lists (Easy)
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
要求:时间复杂度为 O(N),空间复杂度为 O(1)
由于两个链表会有一个交点,那么从两个链表的尾结点到交点之间的所有结点都是相同的。因此先通过两个链表的长度差将指向两个链表的指针调整到同步移动,然后在移动的过程中如果两个指针指向的结点相同,那么就是要找的交点。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null)
return null;
ListNode h1 = headA,h2 = headB;
int len1 = 0,len2 = 0;
while(h1 != null){
len1++;
h1 = h1.next;
}
while(h2 != null){
len2++;
h2 = h2.next;
}
h1 = headA;
h2 = headB;
if(len1 > len2){
int n = len1 - len2;
while(n > 0){
h1 = h1.next;
n--;
}
}else{
int n = len2 - len1;
while(n > 0){
h2 = h2.next;
n--;
}
}
while(h1 != null && h2 != null){
if(h1 == h2)
return h1;
h1 = h1.next;
h2 = h2.next;
}
return null;
}
}
如果只是判断是否存在交点,那么就是另一个问题,即 编程之美 3.6 的问题。有两种解法:
- 把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;
- 或者直接比较两个链表的最后一个节点是否相同。
链表反转
206. Reverse Linked List (Easy)
头插法
public ListNode reverseList(ListNode head) {
ListNode newHead = new ListNode(-1);
while (head != null) {
ListNode next = head.next;
head.next = newHead.next;
newHead.next = head;
head = next;
}
return newHead.next;
}
从有序链表中删除重复节点
83. Remove Duplicates from Sorted List (Easy)
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null)
return null;
ListNode p = head;
TreeSet<Integer> set = new TreeSet<Integer>();
while(p != null){
set.add(p.val);
p = p.next;
}
p = new ListNode(0);
ListNode temp = p;
for(Integer x : set){
ListNode node = new ListNode(x);
temp.next = node;
temp = temp.next;
}
return p.next;
}
}
删除链表的倒数第 n 个节点
19. Remove Nth Node From End of List (Medium)
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if (null == head || 0 == n) {
return null;
}
ListNode fast = head;
while (n > 0) {
fast = fast.next;
n--;
}
if (null == fast) {
return head.next;
}
ListNode slow = head;
while (fast.next != null) {
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return head;
}
}
交换链表中的相邻结点
24. Swap Nodes in Pairs (Medium)
Given 1->2->3->4, you should return the list as 2->1->4->3.
题目要求:不能修改结点的 val 值,O(1) 空间复杂度。
class Solution {
public ListNode swapPairs(ListNode head) {
if (null == head || null == head.next) {
return head;
}
ListNode phead = new ListNode(-1);
phead.next = head;
ListNode p = phead;
while (p != null && p.next != null && p.next.next != null) {
ListNode l1 = p.next;
ListNode l2 = p.next.next;
p.next = l2;
l1.next = l2.next;
l2.next = l1;
p = l2.next;
}
return phead.next;
}
}
链表求和
445. Add Two Numbers II (Medium)
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
题目要求:不能修改原始链表。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (null == l1 || null == l2) {
return null;
}
ListNode head = new ListNode(0);
ListNode p = head;
int len1 = 0, len2 = 0;
ListNode h1 = l1, h2 = l2;
while (h1 != null) {
len1++;
h1 = h1.next;
}
while (h2 != null) {
len2++;
h2 = h2.next;
}
h1 = l1;
h2 = l2;
if (len1 > len2) {
int k = len1 - len2;
while (k-- > 0) {
ListNode node = new ListNode(h1.val);
p.next = node;
p = p.next;
h1 = h1.next;
}
} else if (len2 > len1) {
int k = len2 - len1;
while (k-- > 0) {
ListNode node = new ListNode(h2.val);
p.next = node;
p = p.next;
h2 = h2.next;
}
}
while (h1 != null && h2 != null) {
ListNode node = new ListNode(h1.val + h2.val);
p.next = node;
p = p.next;
h1 = h1.next;
h2 = h2.next;
}
int k = Math.max(len1, len2);
while (k-- > 0) {
p = head;
while (p.next != null) {
if (p.next.val >= 10) {
int val = p.next.val;
p.val += val / 10;
p.next.val = val % 10;
}
p = p.next;
}
}
return head.val == 0 ? head.next : head;
}
}
回文链表
234. Palindrome Linked List (Easy)
题目要求:以 O(1) 的空间复杂度来求解。
切成两半,把后半段反转,然后比较两半是否相等。
class Solution {
public boolean isPalindrome(ListNode head) {
if (null == head || null == head.next) {
return true;
}
ListNode slow = head;
ListNode fast = head.next;
while (fast.next != null) {
slow = slow.next;
fast = fast.next;
if (fast.next != null) {
fast = fast.next;
} else {
break;
}
}
ListNode phead = new ListNode(-1);
ListNode p = slow.next;
ListNode temp = p.next;
while (temp != null) {
p.next = phead.next;
phead.next = p;
p = temp;
temp = temp.next;
}
p.next = phead.next;
phead.next = p;
p = phead.next;
boolean flag = true;
while (p != null) {
if (head.val != p.val) {
flag = false;
break;
}
p = p.next;
head = head.next;
}
return flag;
}
}
链表元素按奇偶聚集
328. Odd Even Linked List (Medium)
Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.
//Method 1
public ListNode oddEvenList(ListNode head) {
if (head == null) {
return head;
}
ListNode odd = head, even = head.next, evenHead = even;
while (even != null && even.next != null) {
odd.next = odd.next.next;
odd = odd.next;
even.next = even.next.next;
even = even.next;
}
odd.next = evenHead;
return head;
}
//Method 2
class Solution {
public ListNode oddEvenList(ListNode head) {
if (null == head || null == head.next || null == head.next.next) {
return head;
}
ListNode phead = new ListNode(-1);
ListNode p = head;
ListNode ph = phead;
int k = 1;
while (p != null && p.next != null && p.next.next != null) {
if (k % 2 == 1) {
ph.next = p.next;
ph = ph.next;
p.next = p.next.next;
} else if (k % 2 == 0){
p = p.next;
}
k++;
}
if (null == p.next) {
p.next = phead.next;
} else if (null == p.next.next) {
if (k % 2 == 0) {
p = p.next;
}
ph.next = p.next;
p.next = phead.next;
}
return head;
}
}