链表习题
1. 逆置链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution
{
public ListNode reverseList(ListNode head)
{
ListNode result=null;
ListNode cur=head;
while(cur!=null)
{
ListNode next=cur.next;
cur.next=result;
result=cur;
cur=next;
}
return result;
}
}
2. 删除链表中重复的结点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
/*
public class ListNode
{
int val;
ListNode next = null;
ListNode(int val)
{
this.val = val;
}
}
*/
public class Solution
{
public ListNode deleteDuplication(ListNode pHead)
{
if (pHead == null)
{
return null;
}
ListNode prev = null;
ListNode p1 = pHead;
ListNode p2 = pHead.next;
while (p2 != null)
{
if (p1.val != p2.val)
{
prev = p1;
p1 = p2;
p2 = p2.next;
}
else
{
while (p2 != null && p2.val == p1.val)
{
p2 = p2.next;
}
if (prev == null)
{
pHead = p2;
}
else
{
prev.next = p2;
}
p1 = p2;
if (p2 != null)
{
p2 = p2.next;
}
}
}
return pHead;
}
}
3. 删除链表中等于给定值 val 的所有节点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution
{
public ListNode removeElements(ListNode head, int val)
{
ListNode cur=head;
ListNode result=null;
ListNode prev=null;
while(cur!=null)
{
ListNode next=cur.next;
if(cur.val==val)
{
if(cur==head)
{
head=cur.next;
}
else
{
prev.next=cur.next;
}
}
else
{
prev=cur;
}
cur=cur.next;
}
return head;
}
}
//法二
class Solution
{
public ListNode removeElements(ListNode head, int val)
{
ListNode tmpHead = new ListNode(-1);
tmpHead.next = head;
ListNode prev = tmpHead;
ListNode cur = head;
while (cur != null)
{
if (cur.val == val)
{
prev.next = cur.next;
}
else
{
prev = cur;
}
cur = cur.next;
}
return tmpHead.next;
}
}
4. 复杂链表的复制
/*
// Definition for a Node.
class Node
{
int val;
Node next;
Node random;
public Node(int val)
{
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution
{
public Node copyRandomList(Node head)
{
if(head==null)
{
return null;
}
Node p1=head;
while(p1!=null)
{
Node p2=new Node(p1.val);
p2.random=null;
p2.next=p1.next;
p1.next=p2;
p1=p2.next;
}
p1=head;
while(p1!=null)
{
if(p1.random!=null)
p1.next.random=p1.random.next;
p1=p1.next.next;
}
p1=head;
Node newHead=head.next;
while(p1.next!=null)
{
Node p2=p1.next;
p1.next=p1.next.next;
p1=p2;
}
return newHead;
}
}
5. 相交链表
输入两个链表,找到两个单链表相交的起始点
//方法一:长度差判断
public class Solution
{
private int getLength(ListNode head)
{
int len = 0;
for (ListNode c = head; c != null; c = c.next)
{
len++;
}
return len;
}
public ListNode getIntersectionNode(ListNode headA, ListNode headB)
{
int lenA = getLength(headA);
int lenB = getLength(headB);
ListNode longer = headA;
ListNode shorter = headB;
int diff = lenA - lenB;
if (lenA < lenB)
{
longer = headB;
shorter = headA;
diff = lenB - lenA;
}
for (int i = 0; i < diff; i++)
{
longer = longer.next;
}
while (longer != shorter)
{
longer = longer.next;
shorter = shorter.next;
}
return longer;
}
}
//方法二:快慢指针
public class Solution
{
public ListNode getIntersectionNode(ListNode headA, ListNode headB)
{
if (headA == null || headB == null)
{
return null;
}
ListNode last = headB;
while (last.next != null)
{
last = last.next;
}
last.next = headB;
ListNode fast = headA;
ListNode slow = headA;
while (fast != null && fast.next != null)
{
slow = slow.next;
fast = fast.next.next;
if (slow == fast)
{
slow = headA;
while (slow != fast)
{
slow = slow.next;
fast = fast.next;
}
last.next = null;
return fast;
}
}
last.next = null;
return null;
}
}
//方法三:思路:
/**定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点
* (在第一轮移动中恰好抹除了长度差)
* 两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
*/
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution
{
public ListNode getIntersectionNode(ListNode headA, ListNode headB)
{
if(headA==null||headB==null)
{
return null;
}
ListNode pA=headA,pB=headB;
//第一轮交换表头,抹掉长度差
//第二轮有交点则相遇
while(pA!=pB)
{
pA=pA==null?headB:pA.next;
pB=pB==null?headA:pB.next;
}
return pA;
}
}
6. 合并两个有序链表
Node merge(Node head1, Node head2)
{
if (head1 == null)
{
return head2;
}
if (head2 == null)
{
return head1;
}
Node result = null;
Node last = null;
Node cur1 = head1;
Node cur2 = head2;
while (cur1 != null && cur2 != null)
{
if (cur1.val <= cur2.val)
{
if (result == null)
{
result = cur1;
}
else
{
last.next = cur1;
}
last = cur1;
cur1 = cur1.next;
}
else
{
if (result == null)
{
result = cur2;
}
else
{
last.next = cur2;
}
last = cur2;
cur2 = cur2.next;
}
}
if (cur1 != null)
{
last.next = cur1;
} else
{
last.next = cur2;
}
return result;
}
//迭代
/**
* Definition for singly-linked list.
* public class ListNode
{
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution
{
public ListNode mergeTwoLists(ListNode l1, ListNode l2)
{
if(l1==null)
{
return l2;
}
if(l2==null)
{
return l1;
}
ListNode result=null;
ListNode last=null;
ListNode cur1=l1;
ListNode cur2=l2;
while(cur1!=null&&cur2!=null)
{
if(cur1.val<=cur2.val)
{
if (result == null)
{
result = cur1;
}
else
{
last.next = cur1;
}
last = cur1;
cur1 = cur1.next;
}
else
{
if (result == null)
{
result = cur2;
}
else
{
last.next = cur2;
}
last = cur2;
cur2 = cur2.next;
}
}
if (cur1 != null)
{
last.next = cur1;
} else
{
last.next = cur2;
}
return result;
}
}
//递归
class Solution
{
public ListNode mergeTwoLists(ListNode l1, ListNode l2)
{
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val <= l2.val)
{
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}
else
{
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
7. 链表的中间结点
给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution
{
private int getLength(ListNode head)
{
int len = 0;
for (ListNode cur = head; cur != null; cur = cur.next)
{
len++;
}
return len;
}
public ListNode middleNode(ListNode head)
{
int len = getLength(head);
int midLen = len / 2;
ListNode node = head;
for (int i = 0; i < midLen; i++)
{
node = node.next;
}
return node;
}
}
//快慢指针
//思路:快指针q每次走2步,慢指针p每次走1步,当q走到末尾时p正好走到中间
class Solution
{
public ListNode middleNode(ListNode head)
{
ListNode q = head, p = head;
while(q!= null && q.next != null)
{
p = p.next;
q = q.next.next;
}
return p;
}
}
8. 链表中倒数第k个结点
//快慢指针:两个指针的位置相差k-1个距离,当快指针走到最后一个节点的时候,
//慢指针指向的位置就是我们要的倒数第k个节点
/*
public class ListNode
{
int val;
ListNode next = null;
ListNode(int val)
{
this.val = val;
}
}*/
public class Solution
{
public ListNode FindKthToTail(ListNode head,int k)
{
ListNode front = head;
ListNode back = head;
for (int i = 0; i < k; i++)
{
if (front == null)
{
return null;
}
front = front.next;
}
while (front != null)
{
back = back.next;
front = front.next;
}
return back;
}
}
//方法二:倒数第K个结点等价于正向的链表长度len-k的结点
/*
public class ListNode
{
int val;
ListNode next = null;
ListNode(int val)
{
this.val = val;
}
}*/
public class Solution
{
public ListNode FindKthToTail(ListNode head,int k)
{
int len=0;
for(ListNode cur=head;cur!=null;cur=cur.next)
{
len++;
}
if(len<k)
{
return null;
}
int step=len-k;
ListNode r=head;
for(int i=0;i<step;i++)
{
r=r.next;
}
return r;
}
}
9. 链表分割
以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前。给定一个链表的头指针 ListNode* pHead,请返回重新排列后的链表的头指针。注意:分割以后保持原来的数据顺序不变。
import java.util.*;
/*
public class ListNode
{
int val;
ListNode next = null;
ListNode(int val)
{
this.val = val;
}
}*/
public class Partition
{
public ListNode partition(ListNode pHead, int x)
{
// < x
ListNode less = null;
ListNode lessLast = null;
// >= x
ListNode great = null;
ListNode greatLast = null;
ListNode cur = pHead;
while (cur != null)
{
if (cur.val < x)
{
if (less == null)
{
less = cur;
}
else
{
lessLast.next = cur;
}
lessLast = cur;
} else
{
if (great == null)
{
great = cur;
}
else
{
greatLast.next = cur;
}
greatLast = cur;
}
cur = cur.next;
}
if (less == null)
{
return great;
}
else
{
lessLast.next = great;
if (greatLast != null)
{
greatLast.next = null;
}
return less;
}
}
}
10. 链表的回文结构
题目描述
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例:
1->2->2->1
返回:true
//思路:利用快慢指针法找到链表的中间结点,对中间结点后的链表进行反转,从头遍历对比元素值是否相等
import java.util.*;
/*
public class ListNode
{
int val;
ListNode next = null;
ListNode(int val)
{
this.val = val;
}
}*/
public class PalindromeList
{
public ListNode getMid(ListNode head)
{
ListNode fast = head;
ListNode slow = head;
while (fast != null&&fast.next!=null)
{
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
public ListNode reverse(ListNode head)
{
ListNode result = null;
ListNode cur = head;
while (cur != null)
{
ListNode next = cur.next;
cur.next = result;
result = cur;
cur = next;
}
return result;
}
public boolean chkPalindrome(ListNode A)
{
ListNode mid = getMid(A);
ListNode h2 = reverse(mid);
ListNode n1 = A;
ListNode n2 = h2;
while (n1 != null && n2 != null)
{
if (n1.val != n2.val)
{
return false;
}
n1 = n1.next;
n2 = n2.next;
}
return true;
}
}
11. 环形链表
给定一个链表,判断链表中是否有环
//快慢指针,快指针一次走两步,慢指针一次走一步,有环两者最终会相遇。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution
{
public boolean hasCycle(ListNode head)
{
if(head==null||head.next==null)
{
return false;
}
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;
}
}