leecode更新

This commit is contained in:
markilue 2022-12-26 13:24:23 +08:00
parent cc16a1c70c
commit a5fca3e288
8 changed files with 455 additions and 6 deletions

View File

@ -2,7 +2,7 @@ package com.markilue.leecode.listnode;
public class swapPairs { public class T04_swapPairs {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -3,7 +3,7 @@ package com.markilue.leecode.listnode;
/** /**
* 删除链表的倒数第N个节点 * 删除链表的倒数第N个节点
*/ */
public class removeNthFromEnd { public class T05_removeNthFromEnd {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -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;
}
}

View File

@ -19,7 +19,7 @@ import java.util.HashSet;
* @Version: 1.0 * @Version: 1.0
*/ */
public class DetectCycle { public class T07_DetectCycle {
@Test @Test

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,6 +1,6 @@
package com.markilue.leecode.listnode.selftry; package com.markilue.leecode.listnode.selftry;
import com.markilue.leecode.listnode.swapPairs; import com.markilue.leecode.listnode.T04_swapPairs;
public class reverseKGroup { public class reverseKGroup {
@ -16,7 +16,7 @@ public class reverseKGroup {
} }
public static class ListNode { public static class ListNode {
int val; int val;
swapPairs.ListNode next; T04_swapPairs.ListNode next;
ListNode() { ListNode() {
} }
@ -25,7 +25,7 @@ public class reverseKGroup {
this.val = val; this.val = val;
} }
ListNode(int val, swapPairs.ListNode next) { ListNode(int val, T04_swapPairs.ListNode next) {
this.val = val; this.val = val;
this.next = next; this.next = next;
} }