相交链表
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode A = headA;
ListNode B = headB;
int lenA = 0,lenB = 0;
//记录两个链表长度
while(A!=null){
A = A.next;
lenA++;
}
while(B!=null){
B = B.next;
lenB++;
}
int count =0;
//记录链表长度差值,让A始终指向较长链表
if(lenA>lenB){
count = lenA-lenB;
A = headA;
B = headB;
}else{
count = lenB - lenA;
A = headB;
B = headA;
}
//较长的A先走
while(count-->0){
A = A.next;
}
//两个链表一起走,最终必相等
while(A!=B){
A = A.next;
B = B.next;
}
//要么是找到交点,要么是两个都走向了null
//直接返回就行
return A;
}
}
环形链表的起始点
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow=head;
ListNode fast=head;
//一个节点不构成环
if(head==null||head.next==null) return null;
while(slow!=null&&fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(slow==fast){
break;
}
}
//在第一个点相遇
if(fast==head){
return head;
}
slow=head;
while(slow!=null&&fast!=null){
slow=slow.next;
fast=fast.next;
if(slow==fast){
return slow;
}
}
return null;
}
}
合并K个升序链表
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode pre=new ListNode(0);
ListNode curr=pre;
//PriorityQueue<ListNode> pq=new PriorityQueue<>((o1,o2)->(o1.val-o2.val));
PriorityQueue<ListNode> pq=new PriorityQueue(new Comparator<ListNode>(){
public int compare(ListNode o1,ListNode o2){
return o1.val-o2.val;
}
});
for(int i=0;i<lists.length;i++){
ListNode listnode=lists[i];
if(listnode!=null)
pq.add(listnode);
}
while(pq.size()!=0){
ListNode head=pq.poll();
//System.out.println(head.val);
ListNode next=head.next;
if(next!=null)
pq.add(next);
head.next=null;
curr.next=head;
curr=head;
}
//System.out.println(pq);
return pre.next;
}
}
优先队列
pq
中的元素个数最多是k
,所以一次poll
或者add
方法的时间复杂度是O(logk)
;所有的链表节点都会被加入和弹出pq
,所以算法整体的时间复杂度是O(Nlogk)
,其中k
是链表的条数,N
是这些链表的节点总数
重排链表
输入:head = [1,2,3,4] 输出:[1,4,2,3]
class Solution {
public void reorderList(ListNode head) {
//将链表分割成两个链表,然后把第二个链表反转,之后在通过两个链表拼接成新的链表。
ListNode fast = head, slow = head;
//求出中点
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
//right就是右半部分 12345 就是45 1234 就是34
ListNode right = slow.next;
//断开左部分和右部分
slow.next = null;
//反转右部分 right就是反转后右部分的起点
right = reverseList(right);
//左部分的起点
ListNode left = head;
//进行左右部分来回连接
while (right != null) {
ListNode next=head.next;
ListNode next2=right.next;
head.next=right;
right.next=next;
head=next;
right=next2;
}
}
public ListNode reverseList(ListNode head) {
ListNode headNode = new ListNode(0);
ListNode cur = head;
ListNode next = null;
while (cur != null) {
next = cur.next;
cur.next = headNode.next;
headNode.next = cur;
cur = next;
}
return headNode.next;
}
}
删除链表的倒数第K个节点
法一:假设链表有
n
个节点,倒数第k
个节点就是正数第n - k + 1
个节点法二:快指针先走K步
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//防止要删除的是第一个节点,所以设置一个辅助节点
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
//进行快指针先走n步
for(int i = 0;i<=n;i++){
fast=fast.next;
}
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}
删除链表中的重复元素
输入:head = [1,2,3,3,4,4,5] 输出:[1,2,5]
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode p=new ListNode(-1);
ListNode pp=p;
boolean flag=true;
while(head!=null){
if(head.next!=null&&head.val!=head.next.val){
pp.next=head;
head=head.next;
pp=pp.next;
pp.next=null;
}
else if(head.next==null){
pp.next=head;
head=head.next;
}
while(head!=null&&head.next!=null&&head.val==head.next.val){
//System.out.println(head.val);
head=head.next;
flag=false;
}
if(flag==false&&head!=null) {
head=head.next;
flag=true;
}
}
return p.next;
}
}
链表排序
归并排序
class Solution {
public ListNode sortList(ListNode head) {
return mergeSort(head);
}
// 归并排序
private ListNode mergeSort(ListNode head){
// 如果没有结点/只有一个结点,无需排序,直接返回
if (head==null||head.next==null) return head;
// 快慢指针找出中位点
ListNode slowp=head,fastp=head.next.next,l,r;
while (fastp!=null&&fastp.next!=null){
slowp=slowp.next;
fastp=fastp.next.next;
}
// 对右半部分进行归并排序
r=mergeSort(slowp.next);
// 链表判断结束的标志:末尾节点.next==null
slowp.next=null;
// 对左半部分进行归并排序
l=mergeSort(head);
return mergeList(l,r);
}
// 合并链表
private ListNode mergeList(ListNode l,ListNode r){
// 临时头节点
ListNode tmpHead=new ListNode(-1);
ListNode p=tmpHead;
while (l!=null&&r!=null){
if (l.val<r.val){
p.next=l;
l=l.next;
}else {
p.next=r;
r=r.next;
}
p=p.next;
}
p.next=l==null?r:l;
return tmpHead.next;
}
}
快排
class Solution {
public ListNode sortList(ListNode head) {
if(head==null||head.next==null) return head;
// 没有条件,创造条件。自己添加头节点,最后返回时去掉即可。
ListNode newHead=new ListNode(-1);
newHead.next=head;
return quickSort(newHead,null);
}
// 带头结点的链表快速排序
private ListNode quickSort(ListNode head,ListNode end){
if (head==end||head.next==end||head.next.next==end) return head;
// 将小于划分点的值存储在临时链表中
ListNode tmpHead=new ListNode(-1);
// partition为划分点,p为链表指针,tp为临时链表指针
ListNode partition=head.next,p=partition,tp=tmpHead;
// 将小于划分点的结点放到临时链表中
while (p.next!=end){
if (p.next.val<partition.val){
tp.next=p.next;
tp=tp.next;
p.next=p.next.next;
}else {
p=p.next;
}
}
// 合并临时链表和原链表,将原链表接到临时链表后面即可
tp.next=head.next;
// 将临时链表插回原链表,注意是插回!(不做这一步在对右半部分处理时就断链了)
head.next=tmpHead.next;
quickSort(head,partition);
quickSort(partition,end);
// 题目要求不带头节点,返回结果时去除
return head.next;
}
}
25. K 个一组翻转链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode pp=new ListNode(0);
ListNode pre=pp;
pp.next=head;
while(head!=null){
for(int i=0;i<k-1;i++){
head=head.next;
if(head==null) return pp.next;
}
//记录下一次反转的起始位置
ListNode head1=head.next;
ListNode left=pre.next;
ListNode[] tmp=reverse(left,head);
tmp[1].next=head1;
pre.next=tmp[0];
pre=tmp[1];
head=head1;
}
return pp.next;
}
//得到反转链表后的首尾节点的数组
public ListNode[] reverse(ListNode first,ListNode tail){
ListNode pre=null;
ListNode ln[]=new ListNode[2];
ln[1]=first;
while(first!=tail){
ListNode next=first.next;
first.next=pre;
pre=first;
first=next;
}
tail.next=pre;
ln[0]=tail;
return ln;
}
}
234. 回文链表
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode slow=head;
ListNode fast=head;
int length=0;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
length++;
}
ListNode curr=slow;
ListNode pre=null;
while(curr!=null){
ListNode next=curr.next;
curr.next=pre;
pre=curr;
curr=next;
length++;
}
while(pre!=null){
if(pre.val!=head.val){return false;}
pre=pre.next;
head=head.next;
}
return true;
}
}