leecode更新
This commit is contained in:
parent
44f6375707
commit
438001b2d4
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue