leecode更新
This commit is contained in:
parent
36913ce39e
commit
b1eeb7c60c
|
|
@ -0,0 +1,64 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import com.markilue.leecode.listnode.ListNode;
|
||||
import com.markilue.leecode.listnode.ListNodeUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-03 10:11
|
||||
*@Description:
|
||||
* TODO 力扣19题 删除链表的倒数第N个节点:
|
||||
* 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T13_RemoveNthFromEnd {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
ListNode root = ListNodeUtils.build(new int[]{1, 2, 3, 4, 5});
|
||||
ListNode listNode = removeNthFromEnd(root, 6);
|
||||
ListNodeUtils.print(listNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 快慢指针:一个先走N步,然后两个指针一起走
|
||||
* @param head
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public ListNode removeNthFromEnd(ListNode head, int n) {
|
||||
ListNode fakeHead = new ListNode();
|
||||
fakeHead.next = head;
|
||||
|
||||
ListNode fast = fakeHead;
|
||||
ListNode slow = fakeHead;
|
||||
|
||||
//快指针先走n步
|
||||
while (fast != null && n != 0) {
|
||||
fast = fast.next;
|
||||
n--;
|
||||
}
|
||||
//n不够
|
||||
if (fast == null) {
|
||||
return fakeHead.next;
|
||||
}
|
||||
|
||||
//快指针走到头
|
||||
while (fast.next != null) {
|
||||
fast = fast.next;
|
||||
slow = slow.next;
|
||||
}
|
||||
|
||||
//删除slow
|
||||
slow.next = slow.next.next;
|
||||
|
||||
return fakeHead.next;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-03 10:29
|
||||
*@Description:
|
||||
* TODO 力扣20题 有效的括号:
|
||||
* 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
|
||||
* 有效字符串需满足:
|
||||
* 左括号必须用相同类型的右括号闭合。
|
||||
* 左括号必须以正确的顺序闭合。
|
||||
* 每个右括号都有一个对应的相同类型的左括号。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T14_IsValid {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String s = "()";
|
||||
System.out.println(isValid(s));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:核心就是对称消除 使用stack消栈
|
||||
* 速度击败48.96% 内存击败43.9% 2ms
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid(String s) {
|
||||
|
||||
char[] chars = s.toCharArray();
|
||||
|
||||
Stack<Character> stack = new Stack<>();
|
||||
Map<Character, Character> map = new HashMap() {{
|
||||
put(')', '(');
|
||||
put(']', '[');
|
||||
put('}', '{');
|
||||
}};
|
||||
|
||||
for (char aChar : chars) {
|
||||
if (!map.containsKey(aChar)) {
|
||||
stack.push(aChar);
|
||||
} else {
|
||||
|
||||
if (stack.isEmpty() || map.get(aChar) != stack.pop()) {//这里记得将判空
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!stack.isEmpty()) {//这里也要记得加判空
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public boolean isValid1(String s) {
|
||||
|
||||
char[] chars = s.toCharArray();
|
||||
|
||||
Deque<Character> stack = new LinkedList<>();
|
||||
Map<Character, Character> map = new HashMap() {{
|
||||
put(')', '(');
|
||||
put(']', '[');
|
||||
put('}', '{');
|
||||
}};
|
||||
|
||||
for (char aChar : chars) {
|
||||
if (!map.containsKey(aChar)) {
|
||||
stack.push(aChar);
|
||||
} else {
|
||||
|
||||
if (stack.isEmpty() || map.get(aChar) != stack.pop()) {//这里记得将判空
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!stack.isEmpty()) {//这里也要记得加判空
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方优秀的解答:使用数组代替stack
|
||||
* 速度击败100% 内存击败29.16% 0ms
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid2(String s) {
|
||||
if(s == null || s.length()==0){
|
||||
return true;
|
||||
}
|
||||
char[] str = s.toCharArray();
|
||||
int N = str.length;
|
||||
int size = 0;
|
||||
char[] stack=new char[N];
|
||||
for (int i=0;i<N;i++){
|
||||
char cha = str[i];
|
||||
if(cha=='('||cha=='['|| cha=='{'){
|
||||
stack[size++] = cha =='('?')':(cha=='['?']':'}');
|
||||
}else {
|
||||
if(size == 0){
|
||||
return false;
|
||||
}
|
||||
char last = stack[--size];
|
||||
if(cha != last ){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size == 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import com.markilue.leecode.listnode.ListNode;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-03 10:50
|
||||
*@Description:
|
||||
* TODO 力扣21题 合并两个有序链表:
|
||||
* 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T15_MergeTwoLists {
|
||||
|
||||
|
||||
/**
|
||||
* 思路:递归,谁小合并谁
|
||||
* 速度击败100% 内存击败83% 0ms
|
||||
* @param list1
|
||||
* @param list2
|
||||
* @return
|
||||
*/
|
||||
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
|
||||
|
||||
if (list1 == null) {
|
||||
return list2;
|
||||
}
|
||||
if (list2 == null) {
|
||||
return list1;
|
||||
}
|
||||
|
||||
ListNode root = new ListNode();
|
||||
if (list1.val < list2.val) {
|
||||
root.val = list1.val;
|
||||
root.next = mergeTwoLists(list1.next, list2);
|
||||
} else {
|
||||
root.val = list2.val;
|
||||
root.next = mergeTwoLists(list1, list2.next);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public ListNode mergeKLists(ListNode[] lists) {
|
||||
if(lists == null || lists.length == 0){
|
||||
return null;
|
||||
}
|
||||
return merge(lists,0,lists.length - 1);
|
||||
}
|
||||
|
||||
public ListNode merge(ListNode[] lists , int left , int right){
|
||||
if(left == right) {return lists[left];}
|
||||
int middle = left + (right - left)/2;
|
||||
ListNode list1 = merge(lists,left,middle);
|
||||
ListNode list2 = merge(lists,middle + 1,right);
|
||||
return mergeTwoList(list1,list2);
|
||||
}
|
||||
|
||||
|
||||
public ListNode mergeTwoList(ListNode head1, ListNode head2){
|
||||
ListNode dummy = new ListNode();
|
||||
ListNode cur = dummy; // cur指向当前合并链表的最后一个
|
||||
while(head1!=null && head2!=null){
|
||||
if(head1.val <= head2.val){
|
||||
cur.next = head1;
|
||||
head1 = head1.next;
|
||||
}else{
|
||||
cur.next = head2;
|
||||
head2 = head2.next;
|
||||
}
|
||||
cur = cur.next;
|
||||
}
|
||||
cur.next = head1==null?head2:head1;
|
||||
return dummy.next;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-03 10:56
|
||||
*@Description:
|
||||
* TODO 力扣22题 括号生成:
|
||||
* 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T16_GenerateParenthesis {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(generateParenthesis(1));
|
||||
}
|
||||
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
StringBuilder cur = new StringBuilder();
|
||||
|
||||
|
||||
/**
|
||||
* 思路:有效的括号 实际上就是前面的(要比)要多那就是有效的括号
|
||||
* 速度击败75.47% 内存击败39.67% 1ms
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public List<String> generateParenthesis(int n) {
|
||||
backtracking(n, 0, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param n 需要生成多少对括号
|
||||
* @param x 当前有多少个(
|
||||
* @param y 当前有多少个)
|
||||
*/
|
||||
public void backtracking(int n, int x, int y) {
|
||||
if (x < y || x > n || y > n) {
|
||||
//非有效括号
|
||||
return;
|
||||
}
|
||||
if (n == x && n == y) {
|
||||
//遍历完了,并且符合要求
|
||||
result.add(new String(cur));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (i == 0) {
|
||||
cur.append('(');
|
||||
backtracking(n, x + 1, y);
|
||||
} else {
|
||||
cur.append(')');
|
||||
backtracking(n, x, y + 1);
|
||||
}
|
||||
cur.deleteCharAt(cur.length() - 1);//回溯
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方最快:本质上与本人一致,只是把判断简化了
|
||||
* 速度击败100% 内存击败66.13% 0ms
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public List<String> generateParenthesis1(int n) {
|
||||
List<String> result = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
backTrack(result, sb, 0, 0, n);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void backTrack(List<String> result, StringBuilder sb, int left, int right, int n) {
|
||||
|
||||
if (sb.length() == n * 2) {
|
||||
result.add(sb.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (left < n) {
|
||||
sb.append('(');
|
||||
backTrack(result, sb, left + 1, right, n);
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
|
||||
if (right < left) {
|
||||
sb.append(')');
|
||||
backTrack(result, sb, left, right + 1, n);
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import com.markilue.leecode.listnode.ListNode;
|
||||
import com.markilue.leecode.listnode.ListNodeUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-03 11:18
|
||||
*@Description:
|
||||
* TODO 力扣23题 合并k个升序链表:
|
||||
* 给你一个链表数组,每个链表都已经按升序排列。
|
||||
* 请你将所有链表合并到一个升序链表中,返回合并后的链表。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T17_MergeKLists {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ListNode[] listNodes = new ListNode[3];
|
||||
listNodes[0] = ListNodeUtils.build(new int[]{1, 4, 5});
|
||||
listNodes[1] = ListNodeUtils.build(new int[]{1,3,4});
|
||||
listNodes[2] = ListNodeUtils.build(new int[]{2, 6});
|
||||
ListNodeUtils.print(mergeKLists(listNodes));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:二分法再合并
|
||||
* 速度击败74.86% 内存击败96.99% 3ms
|
||||
* @param lists
|
||||
* @return
|
||||
*/
|
||||
public ListNode mergeKLists(ListNode[] lists) {
|
||||
|
||||
if (lists.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return split(lists, 0, lists.length - 1);
|
||||
}
|
||||
|
||||
public ListNode split(ListNode[] lists, int start, int end) {
|
||||
if (start == end) {
|
||||
return lists[start];
|
||||
}
|
||||
int mid = start + ((end - start) >> 1);
|
||||
ListNode left = split(lists, start, mid);
|
||||
ListNode right = split(lists, mid + 1, end);
|
||||
|
||||
return merge(left, right);
|
||||
|
||||
}
|
||||
|
||||
public ListNode merge(ListNode list1, ListNode list2) {
|
||||
|
||||
if (list1 == null) {
|
||||
return list2;
|
||||
}
|
||||
if (list2 == null) {
|
||||
return list1;
|
||||
}
|
||||
|
||||
ListNode root = new ListNode();
|
||||
if (list1.val < list2.val) {
|
||||
root.val = list1.val;
|
||||
root.next = merge(list1.next, list2);
|
||||
} else {
|
||||
root.val = list2.val;
|
||||
root.next = merge(list1, list2.next);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方最快:同样是分治法
|
||||
* 速度击败80.97% 内存击败32.68% 2ms
|
||||
* @param lists
|
||||
* @return
|
||||
*/
|
||||
public ListNode mergeKLists1(ListNode[] lists) {
|
||||
if(lists == null || lists.length == 0){
|
||||
return null;
|
||||
}
|
||||
return merge(lists,0,lists.length - 1);
|
||||
}
|
||||
|
||||
public ListNode merge(ListNode[] lists , int left , int right){
|
||||
if(left == right) {return lists[left];}
|
||||
int middle = left + (right - left)/2;
|
||||
ListNode list1 = merge(lists,left,middle);
|
||||
ListNode list2 = merge(lists,middle + 1,right);
|
||||
return mergeTwoList(list1,list2);
|
||||
}
|
||||
|
||||
|
||||
public ListNode mergeTwoList(ListNode head1, ListNode head2){
|
||||
ListNode dummy = new ListNode();
|
||||
ListNode cur = dummy; // cur指向当前合并链表的最后一个
|
||||
while(head1!=null && head2!=null){
|
||||
if(head1.val <= head2.val){
|
||||
cur.next = head1;
|
||||
head1 = head1.next;
|
||||
}else{
|
||||
cur.next = head2;
|
||||
head2 = head2.next;
|
||||
}
|
||||
cur = cur.next;
|
||||
}
|
||||
cur.next = head1==null?head2:head1;
|
||||
return dummy.next;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-03 11:40
|
||||
*@Description:
|
||||
* TODO 力扣31题 下一个排列:
|
||||
* 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
|
||||
* 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
|
||||
* 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。
|
||||
* 更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,
|
||||
* 那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。
|
||||
* 如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
|
||||
* 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
|
||||
* 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
|
||||
* 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
|
||||
* 给你一个整数数组 nums ,找出 nums 的下一个排列。
|
||||
* 必须 原地 修改,只允许使用额外常数空间。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T18_NextPermutation {
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
// int[] nums ={1,2,3};
|
||||
int[] nums ={3,2,1};
|
||||
nextPermutation(nums);
|
||||
System.out.println(Arrays.toString(nums));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:从后往前遍历,寻找第一个当前数比前一个数大的,进行交换 ; 如果找不到就进行整体的排序
|
||||
* 有问题: 没有想象的那么简单
|
||||
* 还有一个思路是: 先有小到大排序 通过回溯(树层去重后),找到原来的数,那么回溯的下一个值就是需要的值
|
||||
* 这有一个问题就是 使用了额外的空间 ,第二是时间复杂度应该为O(2^N)
|
||||
* @param nums
|
||||
*/
|
||||
public void nextPermutation(int[] nums) {
|
||||
|
||||
int i = nums.length - 1;
|
||||
for (; i > 0; i--) {
|
||||
if (nums[i] > nums[i - 1]) {
|
||||
exchange(nums, i, i - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
quickSort(nums);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int[] nums={5,6,4,8,2,9,1,7,3};
|
||||
quickSort(nums);
|
||||
System.out.println(Arrays.toString(nums));
|
||||
}
|
||||
|
||||
public void quickSort(int[] nums) {
|
||||
|
||||
partition(nums,0,nums.length-1);
|
||||
|
||||
}
|
||||
|
||||
public void partition(int[] nums, int i, int j) {
|
||||
if (i >= j) {
|
||||
return;
|
||||
}
|
||||
int mid = sort(nums, i, j);
|
||||
partition(nums, i, mid - 1);//排左边
|
||||
partition(nums, mid + 1, j);//排右边
|
||||
}
|
||||
|
||||
public int sort(int[] nums, int i, int j) {
|
||||
int left = i;
|
||||
int right = j+1;
|
||||
int num = nums[i];
|
||||
|
||||
while (left < right) {
|
||||
|
||||
while (left < j && nums[++left] < num) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (0 < right && nums[--right] > num) {
|
||||
continue;
|
||||
}
|
||||
if (left >= right) {
|
||||
break;
|
||||
}
|
||||
exchange(nums, left, right);
|
||||
|
||||
}
|
||||
exchange(nums, right, i);
|
||||
return right;
|
||||
}
|
||||
|
||||
public void exchange(int[] nums, int i, int j) {
|
||||
int temp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = temp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方解答的思路:两边扫描,具体看笔记
|
||||
* 速度击败100% 内存击败58.73% 0ms
|
||||
* @param nums
|
||||
*/
|
||||
public void nextPermutation1(int[] nums) {
|
||||
int i = nums.length - 2;
|
||||
while (i >= 0 && nums[i] >= nums[i + 1]) {
|
||||
i--;
|
||||
}
|
||||
if (i >= 0) {
|
||||
int j = nums.length - 1;
|
||||
while (j >= 0 && nums[i] >= nums[j]) {
|
||||
j--;
|
||||
}
|
||||
swap(nums, i, j);
|
||||
}
|
||||
reverse(nums, i + 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void swap(int[] nums, int i, int j) {
|
||||
int temp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = temp;
|
||||
}
|
||||
|
||||
public void reverse(int[] nums, int start) {
|
||||
int left = start, right = nums.length - 1;
|
||||
while (left < right) {
|
||||
swap(nums, left, right);
|
||||
left++;
|
||||
right--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 276 B |
Loading…
Reference in New Issue