leecode更新
This commit is contained in:
parent
cc16a1c70c
commit
a5fca3e288
|
|
@ -2,7 +2,7 @@ package com.markilue.leecode.listnode;
|
|||
|
||||
|
||||
|
||||
public class swapPairs {
|
||||
public class T04_swapPairs {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
|
@ -3,7 +3,7 @@ package com.markilue.leecode.listnode;
|
|||
/**
|
||||
* 删除链表的倒数第N个节点
|
||||
*/
|
||||
public class removeNthFromEnd {
|
||||
public class T05_removeNthFromEnd {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
package com.markilue.leecode.listnode;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.listnode
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2022-12-26 11:09
|
||||
*@Description:
|
||||
* TODO 力扣160题 相交链表:
|
||||
* 给你两个单链表的头节点 headA 和 headB ,
|
||||
* 请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T06_GetIntersectionNode {
|
||||
|
||||
/**
|
||||
* 思路:核心在于如何判断两个链表相交了,显然不能通过两个数的值是否相等
|
||||
* 核心是内存,所以用== ?
|
||||
* 使用一个hashset装headA,遍历headB? 时间复杂度O(n)
|
||||
* 速度击败6.13%,内存击败96.59% 8ms
|
||||
* @param headA
|
||||
* @param headB
|
||||
* @return
|
||||
*/
|
||||
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
|
||||
ListNode tempA = headA;
|
||||
ListNode tempB = headB;
|
||||
HashSet<ListNode> set = new HashSet<>();
|
||||
while (tempA != null) {
|
||||
set.add(tempA);
|
||||
tempA = tempA.next;
|
||||
}
|
||||
while (tempB != null) {
|
||||
boolean flag = set.contains(tempB);
|
||||
if (flag) {
|
||||
return tempB;
|
||||
}
|
||||
tempB = tempB.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 代码随想录思路:核心在于如何判断两个链表相交了,显然不能通过两个数的值是否相等
|
||||
* 分别计算出两个链表的长度,如果两个链表相同那么他们的长度应该相同
|
||||
* 因此把两个链表的尾端对齐,从短链表头开始遍历
|
||||
* 速度击败97.96%,内存击败22.84% 1ms
|
||||
* @param headA
|
||||
* @param headB
|
||||
* @return
|
||||
*/
|
||||
public ListNode getIntersectionNode1(ListNode headA, ListNode headB) {
|
||||
ListNode tempA = headA;
|
||||
ListNode tempB = headB;
|
||||
int lengthA = 0;
|
||||
int lengthB = 0;
|
||||
|
||||
//计算A长度
|
||||
while (tempA != null) {
|
||||
lengthA++;
|
||||
tempA = tempA.next;
|
||||
}
|
||||
//计算B长度
|
||||
while (tempB != null) {
|
||||
lengthB++;
|
||||
tempB = tempB.next;
|
||||
}
|
||||
|
||||
//让A成为最长的
|
||||
ListNode curA = headA;
|
||||
ListNode curB = headB;
|
||||
if (lengthA < lengthB) {
|
||||
ListNode temp = curA;
|
||||
curA = curB;
|
||||
curB = temp;
|
||||
int len = lengthA;
|
||||
lengthA = lengthB;
|
||||
lengthB = len;
|
||||
}
|
||||
|
||||
//遍历到两个头
|
||||
int len = lengthA - lengthB;
|
||||
while (len-- > 0) {
|
||||
curA = curA.next;
|
||||
}
|
||||
|
||||
//开始查找
|
||||
while (curA != null && curA != curB) {
|
||||
curA = curA.next;
|
||||
curB = curB.next;
|
||||
}
|
||||
return curA;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方题解中最快:快在不用交换
|
||||
* 先求俩链表的长度,然后将指针pA和pB移动到相同长度的位置
|
||||
* 判断两个指针的节点是否相同,如果相同则返回;
|
||||
* 否则从此相同起点往后移动并判断俩几点是否相同
|
||||
* 速度击败100% 0ms
|
||||
*/
|
||||
public ListNode getIntersectionNode2(ListNode headA, ListNode headB) {
|
||||
int m = 0, n = 0;
|
||||
ListNode pA = headA, pB = headB;
|
||||
for(; pA != null; m++){
|
||||
pA = pA.next;
|
||||
}
|
||||
for(; pB != null; n++){
|
||||
pB = pB.next;
|
||||
}
|
||||
|
||||
pA = headA; pB = headB;
|
||||
// 如果是链表A长了就往后移动m-n个位置
|
||||
if(m > n){
|
||||
for(int i = 0; i < m - n; i++){
|
||||
pA = pA.next;
|
||||
}
|
||||
// 如果链表B长了就往后移动n-m个位置
|
||||
}else if(m < n){
|
||||
for(int i = 0; i < n - m; i++){
|
||||
pB = pB.next;
|
||||
}
|
||||
}
|
||||
|
||||
// 判断相同起点的俩节点是否相同
|
||||
if(pA == pB){
|
||||
return pA;
|
||||
}
|
||||
|
||||
// 否则同时向后移动并判断
|
||||
ListNode ret = null;
|
||||
while(pA != null && pB != null){
|
||||
pA = pA.next;
|
||||
pB = pB.next;
|
||||
if(pA == pB){
|
||||
ret = pA;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public ListNode getIntersectionNode3(ListNode headA, ListNode headB) {
|
||||
ListNode tempA = headA;
|
||||
ListNode tempB = headB;
|
||||
int lengthA = 0;
|
||||
int lengthB = 0;
|
||||
|
||||
//计算A长度
|
||||
while (tempA != null) {
|
||||
lengthA++;
|
||||
tempA = tempA.next;
|
||||
}
|
||||
//计算B长度
|
||||
while (tempB != null) {
|
||||
lengthB++;
|
||||
tempB = tempB.next;
|
||||
}
|
||||
|
||||
//让A成为最长的
|
||||
ListNode curA = headA;
|
||||
ListNode curB = headB;
|
||||
if (lengthA < lengthB) {
|
||||
int len=lengthB-lengthA;
|
||||
for (int i = 0; i < len; i++) {
|
||||
curB=curB.next;
|
||||
}
|
||||
}else {
|
||||
int len=lengthA-lengthB;
|
||||
for (int i = 0; i < len; i++) {
|
||||
curA=curA.next;
|
||||
}
|
||||
}
|
||||
//开始查找
|
||||
while (curA != null && curA != curB) {
|
||||
curA = curA.next;
|
||||
curB = curB.next;
|
||||
}
|
||||
return curA;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方题解法:双指针法,本质上和代码随想录方法一致
|
||||
* 只有当链表 headA和 headB都不为空时,两个链表才可能相交。
|
||||
* 因此首先判断链表 headA和 headB是否为空,如果其中至少有一个链表为空,则两个链表一定不相交,返回 null
|
||||
* 当链表 headA和 headB都不为空时,创建两个指针 pA和 pB,初始时分别指向两个链表的头节点 headA和 headB,然后将两个指针依次遍历两个链表的每个节点。具体做法如下:
|
||||
* 每步操作需要同时更新指针 pA{pA}pA 和 pB{pB}pB。
|
||||
* 如果指针 pA 不为空,则将指针 pA移到下一个节点;如果指针 pB不为空,则将指针 pB移到下一个节点。
|
||||
* 如果指针 pA为空,则将指针 pA移到链表 headB的头节点;如果指针 pB为空,则将指针 pB移到链表 headA的头节点。
|
||||
* 当指针 pA和 pB指向同一个节点或者都为空时,返回它们指向的节点或者 null。
|
||||
* 速度击败97.96% 内存击败9.31% 1ms
|
||||
* @param headA
|
||||
* @param headB
|
||||
* @return
|
||||
*/
|
||||
public ListNode getIntersectionNode4(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ import java.util.HashSet;
|
|||
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class DetectCycle {
|
||||
public class T07_DetectCycle {
|
||||
|
||||
|
||||
@Test
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package com.markilue.leecode.listnode.second;
|
||||
|
||||
import com.markilue.leecode.listnode.ListNode;
|
||||
import com.markilue.leecode.listnode.ListNodeUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.listnode.second
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2022-12-26 09:50
|
||||
*@Description:
|
||||
* TODO 二刷力扣24题 两两交换链表中的节点:
|
||||
* 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。
|
||||
* 你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T04_SwapPairs {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int[] head={1,2,3,4};
|
||||
ListNode root = ListNodeUtils.build(head);
|
||||
ListNodeUtils.print(swapPairs(root));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tes1t(){
|
||||
int[] head={1};
|
||||
ListNode root = ListNodeUtils.build(head);
|
||||
ListNodeUtils.print(swapPairs(root));
|
||||
}
|
||||
|
||||
/**
|
||||
* 自己迭代法思路:速度击败100%,内存击败53.44%
|
||||
* @param head
|
||||
* @return
|
||||
*/
|
||||
public ListNode swapPairs(ListNode head) {
|
||||
|
||||
if (head == null || head.next == null) {
|
||||
return head;
|
||||
}
|
||||
|
||||
ListNode root = new ListNode();
|
||||
root.next = head;
|
||||
ListNode temp = root;
|
||||
while (temp.next != null) {
|
||||
//以1,2,3,4为例
|
||||
if(temp.next.next!=null){
|
||||
//记录2,3,4
|
||||
ListNode temp1=temp.next.next;
|
||||
//1,3,4
|
||||
temp.next.next=temp.next.next.next;
|
||||
//2,1,3,4
|
||||
temp1.next=temp.next;
|
||||
//root,2,1,3,4
|
||||
temp.next=temp1;
|
||||
//后移继续遍历
|
||||
temp=temp.next.next;
|
||||
}else {
|
||||
temp=temp.next;
|
||||
}
|
||||
}
|
||||
return root.next;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方迭代法
|
||||
* @param head
|
||||
* @return
|
||||
*/
|
||||
public ListNode swapPairs1(ListNode head) {
|
||||
|
||||
ListNode dummyNode = new ListNode(0);
|
||||
dummyNode.next = head;
|
||||
ListNode prev = dummyNode;
|
||||
|
||||
while (prev.next != null && prev.next.next != null) {
|
||||
ListNode temp = head.next.next; // 缓存 next
|
||||
prev.next = head.next; // 将 prev 的 next 改为 head 的 next
|
||||
head.next.next = head; // 将 head.next(prev.next) 的next,指向 head
|
||||
head.next = temp; // 将head 的 next 接上缓存的temp
|
||||
prev = head; // 步进1位
|
||||
head = head.next; // 步进1位
|
||||
}
|
||||
return dummyNode.next;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方递归法
|
||||
* @param head
|
||||
* @return
|
||||
*/
|
||||
public ListNode swapPairs2(ListNode head) {
|
||||
// base case 退出提交
|
||||
if(head == null || head.next == null) return head;
|
||||
// 获取当前节点的下一个节点
|
||||
ListNode next = head.next;
|
||||
// 进行递归,先解决后面的
|
||||
ListNode newNode = swapPairs(next.next);
|
||||
// 这里进行交换
|
||||
next.next = head;
|
||||
head.next = newNode;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.markilue.leecode.listnode.second;
|
||||
|
||||
import com.markilue.leecode.listnode.ListNode;
|
||||
import com.markilue.leecode.listnode.ListNodeUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.listnode.second
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2022-12-26 10:33
|
||||
*@Description:
|
||||
* TODO 二刷19题 删除链表的倒数第 N 个结点:
|
||||
* 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T05_RemoveNthFromEnd {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int[] head={1,2,3,4,5};
|
||||
int n = 5;
|
||||
ListNode root = ListNodeUtils.build(head);
|
||||
ListNodeUtils.print(removeNthFromEnd(root,n));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
int[] head={1};
|
||||
int n = 1;
|
||||
ListNode root = ListNodeUtils.build(head);
|
||||
ListNodeUtils.print(removeNthFromEnd(root,n));
|
||||
}
|
||||
|
||||
/**
|
||||
* 自己思路迭代法:
|
||||
* 双指针:一个比另一个多走n,然后另一个到最末尾的时候,这个刚好到要删的地方
|
||||
* 速度击败100%,内存击败95.42%
|
||||
* @param head
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public ListNode removeNthFromEnd(ListNode head, int n) {
|
||||
//弄个虚拟头结点,方便删除头结点
|
||||
ListNode root = new ListNode();
|
||||
root.next=head;
|
||||
ListNode fast=root;
|
||||
ListNode slow=root;
|
||||
//往前置一位,找到要删除的前一个
|
||||
for (int i = 0; i < n; i++) {
|
||||
fast=fast.next;
|
||||
}
|
||||
|
||||
//让快指针走到头
|
||||
while (fast.next!=null){
|
||||
fast=fast.next;
|
||||
slow=slow.next;
|
||||
}
|
||||
|
||||
//慢指针进行删除
|
||||
if(slow.next!=null){
|
||||
slow.next=slow.next.next;
|
||||
}
|
||||
return root.next;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.markilue.leecode.listnode.second;
|
||||
|
||||
import com.markilue.leecode.listnode.ListNode;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.listnode.second
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2022-12-26 12:36
|
||||
*@Description:
|
||||
* TODO 二刷 力扣142题 环形链表 II:
|
||||
* 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
|
||||
* 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
|
||||
* 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。
|
||||
* 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
|
||||
* 不允许修改 链表。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T07_DetectCycle {
|
||||
|
||||
/**
|
||||
* 思路:快慢指针:一个一次走一步,一个一次走两步,如果有环那么他们一定能相遇:
|
||||
* 通过推导可知:从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点
|
||||
* @param head
|
||||
* @return
|
||||
*/
|
||||
public ListNode detectCycle(ListNode head) {
|
||||
if(head==null||head.next==null){
|
||||
return null;
|
||||
}
|
||||
ListNode root = new ListNode();
|
||||
root.next=head;
|
||||
ListNode fast=root;
|
||||
ListNode slow=root;
|
||||
|
||||
while(fast!=null&&fast.next!=null){
|
||||
fast=fast.next.next;
|
||||
slow=slow.next;
|
||||
//让两者相遇
|
||||
if(fast==slow){
|
||||
//从头结点出发一个,再从相遇节点出发一个
|
||||
ListNode temp=root;
|
||||
while (temp!=slow){
|
||||
temp=temp.next;
|
||||
slow=slow.next;
|
||||
}
|
||||
return slow;
|
||||
}
|
||||
}
|
||||
//找不到相遇的
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.markilue.leecode.listnode.selftry;
|
||||
|
||||
import com.markilue.leecode.listnode.swapPairs;
|
||||
import com.markilue.leecode.listnode.T04_swapPairs;
|
||||
|
||||
public class reverseKGroup {
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ public class reverseKGroup {
|
|||
}
|
||||
public static class ListNode {
|
||||
int val;
|
||||
swapPairs.ListNode next;
|
||||
T04_swapPairs.ListNode next;
|
||||
|
||||
ListNode() {
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ public class reverseKGroup {
|
|||
this.val = val;
|
||||
}
|
||||
|
||||
ListNode(int val, swapPairs.ListNode next) {
|
||||
ListNode(int val, T04_swapPairs.ListNode next) {
|
||||
this.val = val;
|
||||
this.next = next;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue