leecode更新

This commit is contained in:
markilue 2023-03-14 17:41:45 +08:00
parent 44f6375707
commit 438001b2d4
4 changed files with 474 additions and 0 deletions

View File

@ -0,0 +1,200 @@
package com.markilue.leecode.hot100;
import com.markilue.leecode.listnode.ListNode;
import com.markilue.leecode.listnode.ListNodeUtils;
import org.junit.Test;
import java.util.List;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-14 09:59
*@Description:
* TODO 力扣148题 排序链表:
* 给你链表的头结点 head 请将其按 升序 排列并返回 排序后的链表
*@Version: 1.0
*/
public class T56_SortList {
@Test
public void test() {
int[] head = {4, 2, 1, 3};
ListNode root = ListNodeUtils.build(head);
ListNode listNode = sortList(root);
ListNodeUtils.print(listNode);
}
/**
* 思路:尝试归并排序
* 速度击败21.59% 内存击败11.8% 16ms
* @param head
* @return
*/
public ListNode sortList(ListNode head) {
if(head==null){
return head;
}
ListNode temp = head;
int length = 0;
while (temp != null) {
length++;
temp = temp.next;
}
return divide(head, 0, length - 1);
}
public ListNode divide(ListNode root, int start, int end) {
if (start >= end) {
return new ListNode(root.val);
}
int mid = start + ((end - start) >> 1);
int temp = mid - start;
ListNode midNode = root;
//root移动mid位
while (temp-- >= 0) {
midNode = midNode.next;
}
ListNode node1 = divide(root, start, mid);
ListNode node2 = divide(midNode, mid + 1, end);
return MergeSort(node1, node2);
}
public ListNode MergeSort(ListNode root1, ListNode root2) {
//两个都不是null,开始归并
ListNode head = new ListNode();
ListNode temp = head;
while (root1 != null && root2 != null) {
if (root1.val < root2.val) {
temp.next = new ListNode(root1.val);
root1 = root1.next;
} else {
temp.next = new ListNode(root2.val);
root2 = root2.next;
}
temp = temp.next;
}
if (root1 == null) {
temp.next = root2;
} else {
temp.next = root1;
}
return head.next;
}
/**
* 官方归并排序:使用快慢指针遍历到中间位置
* 速度击败46.29% 内存击败88.11% 12ms
* @param head
* @return
*/
public ListNode sortList1(ListNode head) {
return sortList(head, null);
}
public ListNode sortList(ListNode head, ListNode tail) {
if (head == null) {
return head;
}
if (head.next == tail) {
head.next = null;
return head;
}
ListNode slow = head, fast = head;
while (fast != tail) {
slow = slow.next;
fast = fast.next;
if (fast != tail) {
fast = fast.next;
}
}
ListNode mid = slow;
ListNode list1 = sortList(head, mid);
ListNode list2 = sortList(mid, tail);
ListNode sorted = merge(list1, list2);
return sorted;
}
public ListNode merge(ListNode head1, ListNode head2) {
ListNode dummyHead = new ListNode(0);
ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
while (temp1 != null && temp2 != null) {
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
if (temp1 != null) {
temp.next = temp1;
} else if (temp2 != null) {
temp.next = temp2;
}
return dummyHead.next;
}
/**
* 官方最快:时间复杂度O(N),直接记录各个值的数量直接根据数量进行构造
* 速度击败99.74% 内存击败11.48% 3ms
* @param head
* @return
*/
public ListNode sortList2(ListNode head) {
if (head == null) {
return null;
}
int max = head.val;
int min = head.val;
ListNode node = head.next;
//记录链表中的最大值最小值
while (node != null) {
int val = node.val;
if (val > max) {
max = val;
}
if (val < min) {
min = val;
}
node = node.next;
}
//记录每个值的数量
int[] count = new int[max - min + 1];
node = head;
while (node != null) {
count[node.val - min]++;
node = node.next;
}
//直接根据每个值的数量进行构造
node = head;
max -= min;
for (int i = 0; i <= max; i++) {
int val = min + i;
while (count[i]-- > 0) {
node.val = val;
node = node.next;
}
}
return head;
}
}

View File

@ -0,0 +1,118 @@
package com.markilue.leecode.hot100;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-14 10:59
*@Description:
* TODO 力扣152题 乘积最大子数组:
* 给你一个整数数组 nums 请你找出数组中乘积最大的非空连续子数组该子数组中至少包含一个数字并返回该子数组所对应的乘积
* 测试用例的答案是一个 32- 整数
* 子数组 是数组的连续子序列
*@Version: 1.0
*/
public class T57_MaxProduct {
@Test
public void test() {
int[] nums = {-2, 3, -4};
System.out.println(maxProduct(nums));
}
/**
* 思路:动态规划法:
* TODO DP五部曲:
* 1.dp定义: dp[i][0]表示不要当前数的最大值 dp[i][1]表示要当前数的最大值
* 2.dp状态转移方程:
* 1.dp[i][0] 不要当前的数
* dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1])
* 2.dp[i][1] 要当前的数
* dp[i][1]=nums[i]
* dp[i][2]=dp[i-1][1]*nums[i]
* 3.dp初始化:dp[i][0]=Integer.Min dp[i][1]=nums[i]
* 4.dp遍历顺序:
* 5.dp举例推导:以nums=[2,3,-2,4]为例
* [2 3 -2 4]
* dp0: m 2 6 6
* dp1: 2 6 -2 4
* 尚且存在问题: 当前位置的最优解未必是前一个位置的最优解得出来的
* 只能过150个用例 [2,-5,-2,-4,3]无法通过 输出20 真实结果24
* @param nums
* @return
*/
public int maxProduct(int[] nums) {
int[][] dp = new int[nums.length][3];
dp[0][0] = Integer.MIN_VALUE;
dp[0][1] = nums[0];
dp[0][2] = nums[0];
int result = nums[0];
for (int i = 1; i < nums.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);
dp[i][1] = Math.max(dp[i - 1][1] * nums[i], nums[i]);
dp[i][2] = dp[i - 1][2] * nums[i];
if (result < dp[i][0]) result = dp[i][0];
if (result < dp[i][1]) result = dp[i][1];
if (result < dp[i][2]) result = dp[i][2];
}
return result;
}
/**
* 官方题解: 也是动态规划法
* 1.根据当前位置的数是整数还是负数来进行判断
* 如果当前位置为正数 则希望前一个数尽可能的大
* 如果当前位置为负数 则希望前一个数尽可能的小
* 所以记录前一个数最大值和最小值
* @param nums
* @return
*/
public int maxProduct1(int[] nums) {
int length = nums.length;
int[] maxF = new int[length];
int[] minF = new int[length];
System.arraycopy(nums, 0, maxF, 0, length);
System.arraycopy(nums, 0, minF, 0, length);
int result=maxF[0];
for (int i = 1; i < length; ++i) {
maxF[i] = Math.max(maxF[i - 1] * nums[i], Math.max(nums[i], minF[i - 1] * nums[i]));
minF[i] = Math.min(minF[i - 1] * nums[i], Math.min(nums[i], maxF[i - 1] * nums[i]));
if(result<maxF[i])result=maxF[i];
}
return result;
}
/**
* 滚动数组优化
* 速度击败66.26% 内存击败42.45% 2ms
* @param nums
* @return
*/
public int maxProduct2(int[] nums) {
int length = nums.length;
int maxF = nums[0];
int minF = nums[0];
int result=nums[0];
int temp;
for (int i = 1; i < length; ++i) {
temp=maxF;
maxF = Math.max(maxF * nums[i], Math.max(nums[i], minF * nums[i]));
minF = Math.min(minF * nums[i], Math.min(nums[i], temp * nums[i]));
if(result<maxF)result=maxF;
}
return result;
}
}

View File

@ -0,0 +1,90 @@
package com.markilue.leecode.hot100;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.PriorityQueue;
import java.util.Stack;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-14 11:40
*@Description:
* TODO 力扣155题 最小栈:
* 设计一个支持 push pop top 操作并能在常数时间内检索到最小元素的栈
* 实现 MinStack :
* MinStack() 初始化堆栈对象
* void push(int val) 将元素val推入堆栈
* void pop() 删除堆栈顶部的元素
* int top() 获取堆栈顶部的元素
* int getMin() 获取堆栈中的最小元素
*@Version: 1.0
*/
public class T58_MinStack {
public PriorityQueue<Integer> queue;
public Stack<Integer> stack;
//核心:又要有栈结构,又要在常数时间检索最小 ->一个栈 一个优先队列?
//通过 速度击败29.61% 内存击败41.67% 5ms
public T58_MinStack() {
queue=new PriorityQueue<>();
stack=new Stack<>();
}
public void push(int val) {
stack.push(val);
queue.offer(val);
}
public void pop() {
Integer pop = stack.pop();
queue.remove(pop);
}
public int top() {
return stack.peek();
}
public int getMin() {
return queue.peek();
}
}
/**
* 官方解法:使用minStack来记录最小值这时只要不pop那个最小值stack就pop出的永远是那个最小值
* 速度击败94.9% 内存击败23.54% 4ms
*/
class MinStack {
private Deque<Integer> stack;
private Deque<Integer> minStack;
public MinStack() {
stack = new ArrayDeque<>();
minStack = new ArrayDeque<>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int val) {
stack.push(val);
minStack.push(Math.min(minStack.peek(), val));
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}

View File

@ -0,0 +1,66 @@
package com.markilue.leecode.hot100;
import com.markilue.leecode.listnode.ListNode;
import java.util.HashSet;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-14 11:55
*@Description:
* TODO 力扣160题 相交链表:
* 给你两个单链表的头节点 headA headB 请你找出并返回两个单链表相交的起始节点如果两个链表不存在相交节点返回 null
*
*@Version: 1.0
*/
public class T59_GetIntersectionNode {
/**
* 思路1:hashset记录法
* 速度击败21.37% 内存击败87.13%
* @param headA
* @param headB
* @return
*/
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
HashSet<ListNode> set = new HashSet<>();
while (headA != null) {
set.add(headA);
headA = headA.next;
}
while (headB != null) {
if (set.contains(headB)) {
return headB;
}
headB = headB.next;
}
return null;
}
/**
* 两个分别走
* 速度击败97.91% 内存击败56.97% 1ms
*/
public ListNode getIntersectionNode1(ListNode headA, ListNode headB) {
ListNode tempA = headA;
ListNode tempB = headB;
while (tempA!= tempB) {
//如果不相交也会出去因为两个最后都会遍历完A和B然后都为null出去
tempA = tempA == null ? headB : tempA.next;
tempB = tempB == null ? headA : tempB.next;
}
return tempA;
}
}