链表
Solution148排序链表、Solution86分隔链表、Solution23合并K个升序链表、Solution160相交链表、Solution234回文链表、Solution328奇偶链表、Solution237删除链表中的特定元素、Solution24两两交换链表中的节点、Solution61旋转链表、Solution138复制带随机指针的链表、Solution24两两交换链表中的节点、
Solution148排序链表
给你链表的头结点
head
,请将其按 升序 排列并返回 排序后的链表 。
使用归并排序
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;
}
}
Solution86分隔链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
虚拟头结点,pq各自带领一片分区,最后连接起来
public class S86分隔链表 {
public ListNode partition(ListNode head, int x) {
ListNode dummyHead1 = new ListNode(0);
ListNode dummyHead2 = new ListNode(0);
ListNode p = dummyHead1;
ListNode q = dummyHead2;
while (head != null) {
if (head.val < x) {
p.next = head;
head = head.next;
p = p.next;
p.next = null;
} else {
q.next = head;
head = head.next;
q = q.next;
q.next = null;
}
}
p.next = dummyHead2.next;
return dummyHead1.next;
}
}
Solution24两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
- 找终止条件:本题终止条件很明显,当递归到链表为空或者链表只剩一个元素的时候,没得交换了,自然就终止了。
- 找返回值:返回给上一层递归的值应该是已经交换完成后的子链表。
- 单次的过程:因为递归是重复做一样的事情,所以从宏观上考虑,只用考虑某一步是怎么完成的。我们假设待交换的俩节点分别为head和next,next的应该接受上一级返回的子链表(参考第2步)。就相当于是一个含三个节点的链表交换前两个节点
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
// 获取当前节点的下一个节点
ListNode next = head.next;
head.next = swapPairs(next.next);
next.next = head;
return next;
}
Solution138复制带随机指针的链表
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。
在这里可以用hashmap映射,也可以在原表上复制一个兄弟表出来,组合在拆开
public class S复杂链表的复制 {
public static Node copyListWithRand(Node head) {
if (head == null) {
return null;
}
Node cur = head;
Node next = null;
//建兄弟节点 1 -> 1' -> 2
while (cur != null) {
next = cur.next;
cur.next = new Node(cur.val);
cur.next.next = next;
cur = next;
}
cur = head;
Node curCopy = null;
//连接随机节点
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
curCopy.random = cur.random != null ? cur.random.next : null;
cur = next;
}
Node res = head.next;
cur = head;
//切断
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
cur.next = next;
curCopy.next = next != null ? next.next : null;
cur = next;
}
return res;
}
}
Solution23.合并K个升序链表
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
直接合并再排序
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0){
return null;
}
ArrayList<Integer> nums = new ArrayList<>();
for (ListNode head : lists) {
ListNode p = head;
while (p != null) {
nums.add(p.val);
p = p.next;
}
}
Collections.sort(nums);
ListNode head = new ListNode(-1);
ListNode p = head;
for (Integer num : nums) {
ListNode node = new ListNode(num);
p.next = node;
p = p.next;
}
return head.next;
}
}
Solution160相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
public class S160相交链表 {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null ){
return null;
}
ListNode p1 = headA;
ListNode p2 = headB;
while (p1 != p2){
p1 = p1 == null ? headB : p1.next;//如果p1是空就从b开始走,不是空就下一个
p2 = p2 == null ? headA : p2.next;
}
return p1;
}
}
Solution234回文链表
给你一个单链表的头节点
head
,请你判断该链表是否为回文链表。如果是,返回true
;否则,返回false
。
快慢指针把链表分成相等两部分,互相遍历找相等,注意fast指向什么表明链表长度奇偶。
public class S234回文链表 {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null){
return true;
}
ListNode slow = head,fast = head;
ListNode p = null,pre = null;
while (fast != null && fast.next != null){
p = slow;
slow = slow.next;
fast = fast.next.next;
p.next = pre;
pre = p;
}
if (fast != null){
slow = slow.next;
//如果fast不指向空代表是奇数个数,让slow指向头结点的下一条;
}
//一一对应判断只要有不一样的就错
while (p != null && slow != null){
if (p.val != slow.val){
return false;
}
p = p.next;
slow = slow.next;
}
return true;
}
}
Solution328奇偶链表
给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。
第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。
请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。
你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。
就是改变链表顺序再把两个连起来。
public class S328奇偶链表 {
public ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null){
return head;
}
ListNode ji = head;
ListNode ou = head.next;
ListNode ouhead = ou;
while (ou != null && ou.next != null){
ji.next = ji.next.next;
ou.next = ou.next.next;
ji = ji.next;
ou = ou.next;
}
ji.next = ouhead;
return head;
}
}
Solution237删除链表中的特定元素
请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点 。
题目数据保证需要删除的节点 不是末尾节点 。
题目给的node就是要删除的节点,链表中删除节点只需要断掉它跟前后的联系,找到人替换自己,再把那个人干掉
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val; //变成下个倒霉蛋
node.next = node.next.next; //把倒霉蛋干掉。
}
}
Solution24两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
迭代法
Solution61旋转链表
给你一个链表的头节点
head
,旋转链表,将链表每个节点向右移动k
个位置。
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if (head == null || head.next == null || k == 0 ){
return head;
}
int count = 1;//统计总个数
ListNode temp = head;
while (temp.next != null) {
count++;
temp = temp.next;
}
k %= count;
//排除k为0时,然后连接首尾,找到k点续到头部
temp.next = head;
for (int i = 0 ;i < count - k ; i++) {
temp = temp.next;
}
ListNode newHead = temp.next;
temp.next = null;
return newHead;
}
}