Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
764aae3459
|
|
@ -9,6 +9,33 @@
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>RELEASE</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<artifactId>DataStructures</artifactId>
|
<artifactId>DataStructures</artifactId>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.atguigu.sort.selftry;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: DataStructures_Algorithm
|
||||||
|
*@BelongsPackage: com.atguigu.sort.selftry
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-03-31 10:26
|
||||||
|
*@Description: TODO 尝试堆排序
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class HeapSort {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
int[] arr = {20, 50, 45, 40, 35,10,30,15,25};
|
||||||
|
//测试80000个数据进行测试
|
||||||
|
// int[] arr = new int[200];
|
||||||
|
// for (int i = 0; i < arr.length; i++) {
|
||||||
|
// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数
|
||||||
|
// }
|
||||||
|
heapSort(arr);
|
||||||
|
System.out.println(Arrays.toString(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void heapSort(int[] arr) {
|
||||||
|
|
||||||
|
if (arr == null) return;
|
||||||
|
//从最后一个非叶子节点开始进行堆化
|
||||||
|
for (int i = arr.length / 2 - 1; i >= 0; i--) {
|
||||||
|
adjustHeap(arr, i, arr.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//进行交换
|
||||||
|
int temp;
|
||||||
|
for (int i = arr.length - 1; i > 0; i--) {
|
||||||
|
temp = arr[i];
|
||||||
|
arr[i] = arr[0];
|
||||||
|
arr[0] = temp;
|
||||||
|
adjustHeap(arr, 0, i);//把交换完的i放在合适的位置
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void adjustHeap(int[] arr, int i, int length) {
|
||||||
|
|
||||||
|
int temp = arr[i];//记录下以前位置的值
|
||||||
|
|
||||||
|
for (int j = 2 * i + 1; j < length; j++) {
|
||||||
|
//比较左右节点哪一个更大
|
||||||
|
if (j + 1 < length && arr[j] < arr[j + 1]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (arr[j] > temp) {
|
||||||
|
//需要进行交换
|
||||||
|
arr[i] = arr[j];
|
||||||
|
i = j;//后续比较j位置的值了
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr[i] = temp;//找到合适的位置放temp
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.atguigu.tree;
|
package com.atguigu.tree;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -17,44 +19,57 @@ public class HeapSort {
|
||||||
// System.out.println(Arrays.toString(arr));
|
// System.out.println(Arrays.toString(arr));
|
||||||
|
|
||||||
//测试80000个数据进行测试
|
//测试80000个数据进行测试
|
||||||
int[] arr =new int[8000000];
|
int[] arr = new int[8000000];
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
arr[i] = (int)(Math.random()*8000000); //生成一个[0,80000]的数
|
arr[i] = (int) (Math.random() * 8000000); //生成一个[0,80000]的数
|
||||||
}
|
}
|
||||||
Date date1 = new Date();
|
Date date1 = new Date();
|
||||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
String date1Str = simpleDateFormat.format(date1);
|
String date1Str = simpleDateFormat.format(date1);
|
||||||
System.out.println("排序前的时间:"+date1Str); //排序前的时间:2022-02-15 21:19:36
|
System.out.println("排序前的时间:" + date1Str); //排序前的时间:2022-02-15 21:19:36
|
||||||
|
|
||||||
heapSort(arr);
|
heapSort(arr);
|
||||||
Date date2 = new Date();
|
Date date2 = new Date();
|
||||||
String date2Str = simpleDateFormat.format(date2);
|
String date2Str = simpleDateFormat.format(date2);
|
||||||
System.out.println("排序后的时间:"+date2Str); //排序后的时间:2022-02-15 21:19:40
|
System.out.println("排序后的时间:" + date2Str); //排序后的时间:2022-02-15 21:19:40
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] arr = {20, 50, 45, 40, 35,10,30,15,25};
|
||||||
|
//测试80000个数据进行测试
|
||||||
|
// int[] arr = new int[200];
|
||||||
|
// for (int i = 0; i < arr.length; i++) {
|
||||||
|
// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数
|
||||||
|
// }
|
||||||
|
heapSort(arr);
|
||||||
|
System.out.println(Arrays.toString(arr));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编写一个堆排序的方法
|
* 编写一个堆排序的方法
|
||||||
*/
|
*/
|
||||||
public static void heapSort(int[] arr) {
|
public static void heapSort(int[] arr) {
|
||||||
|
|
||||||
//TODO (1)将无序序列构建成一个堆,根据升序降序需求选择大顶堆或者小顶堆
|
//TODO (1)将无序序列构建成一个堆,根据升序降序需求选择大顶堆或者小顶堆
|
||||||
//arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点
|
// arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点;
|
||||||
for (int i = arr.length/2-1; i >= 0; i--) {
|
// arr.length/2-1是关键,是adjustHeap前提的满足条件的前提
|
||||||
adjustHeap(arr,i,arr.length);
|
for (int i = arr.length / 2 - 1; i >= 0; i--) {
|
||||||
|
adjustHeap(arr, i, arr.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int temp=0;
|
int temp = 0;
|
||||||
//TODO (2)将顶对元素与末尾元素交换,将最大元素放置在数组末尾
|
//TODO (2)将顶对元素与末尾元素交换,将最大元素放置在数组末尾
|
||||||
//TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,贩毒执行调整+交换步骤,直到整个序列有序
|
//TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序
|
||||||
for (int i = arr.length-1; i >0; i--) {
|
for (int i = arr.length - 1; i > 0; i--) {
|
||||||
//交换
|
//交换
|
||||||
temp=arr[i];
|
temp = arr[i];
|
||||||
arr[i]=arr[0];
|
arr[i] = arr[0];
|
||||||
arr[0]=temp;
|
arr[0] = temp;
|
||||||
adjustHeap(arr,0,i);
|
adjustHeap(arr, 0, i);//主要就是利用堆顶元素就是最大值来进行处理的
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +77,7 @@ public class HeapSort {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前提:该节点的所有子节点都已经是大顶堆了
|
* TODO 前提:该节点的所有子节点都已经是大顶堆了,因为这里需要break
|
||||||
* 将以第i个位置为根节点时以下树,调整成一个大顶堆
|
* 将以第i个位置为根节点时以下树,调整成一个大顶堆
|
||||||
*
|
*
|
||||||
* @param arr 待调整的数组
|
* @param arr 待调整的数组
|
||||||
|
|
@ -76,20 +91,22 @@ public class HeapSort {
|
||||||
//开始调整
|
//开始调整
|
||||||
//说明:j = i * 2 + 1 ;这里k就是i节点的左子节点
|
//说明:j = i * 2 + 1 ;这里k就是i节点的左子节点
|
||||||
for (int j = i * 2 + 1; j < length; j = j * 2 + 1) {
|
for (int j = i * 2 + 1; j < length; j = j * 2 + 1) {
|
||||||
|
//TODO 1.寻找左右节点哪一个更大
|
||||||
if (j + 1 < length && arr[j] < arr[j + 1]) {
|
if (j + 1 < length && arr[j] < arr[j + 1]) {
|
||||||
//左子节点的值小于右子节点的值
|
//左子节点的值小于右子节点的值
|
||||||
j++; //j指向右子节点
|
j++; //j指向右子节点
|
||||||
}
|
}
|
||||||
|
//TODO 2.用左右节点中大值去和他的父节点比较;如果小了直接将父节点变成那个最大的值
|
||||||
if (arr[j] > temp) {
|
if (arr[j] > temp) {
|
||||||
//如果子节点大于父节点
|
//如果子节点大于父节点
|
||||||
arr[i] = arr[j];//把较大的值赋给当前节点
|
arr[i] = arr[j];//把较大的值赋给当前节点
|
||||||
i = j; //将i指向j,继续循环比较
|
i = j; //将i指向j,继续循环比较
|
||||||
}else {
|
} else {
|
||||||
break;
|
break;//左右子节点都比父节点小,直接break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//当for循环结束后,我们已经将以i为父节点的树的最大值,放在了i的位置
|
//当for循环结束后,我们已经将以i为父节点的树的最大值,放在了i的位置
|
||||||
arr[i]=temp; //将temp值放在调整后的位置
|
arr[i] = temp; //将temp值放在调整后的位置
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,217 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-03-13 17:13
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣146题 LRU缓存:
|
||||||
|
* 请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。
|
||||||
|
* 实现 LFUCache 类:
|
||||||
|
* LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象
|
||||||
|
* int get(int key) - 如果键 key 存在于缓存中,则获取键的值,否则返回 -1 。
|
||||||
|
* void put(int key, int value) - 如果键 key 已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量 capacity 时,则应该在插入新项之前,移除最不经常使用的项。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近最久未使用 的键。
|
||||||
|
* 为了确定最不常使用的键,可以为缓存中的每个键维护一个 使用计数器 。使用计数最小的键是最久未使用的键。
|
||||||
|
* 当一个键首次插入到缓存中时,它的使用计数器被设置为 1 (由于 put 操作)。对缓存中的键执行 get 或 put 操作,使用计数器的值将会递增。
|
||||||
|
* 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T55_LFUCache {
|
||||||
|
|
||||||
|
Map<Integer, Node> cache;
|
||||||
|
Map<Integer, NodeList> freqMap;
|
||||||
|
int capacity;
|
||||||
|
int min;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
|
||||||
|
public T55_LFUCache() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public T55_LFUCache(int capacity) {
|
||||||
|
this.capacity = capacity;
|
||||||
|
cache = new HashMap<>();
|
||||||
|
freqMap = new HashMap<>();
|
||||||
|
min = 0;
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get(int key) {
|
||||||
|
Node node = cache.get(key);
|
||||||
|
if (node == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
freqInc(node);
|
||||||
|
return node.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(int key, int value) {
|
||||||
|
if (capacity == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Node node = cache.get(key);
|
||||||
|
if (node != null) {
|
||||||
|
//更新即可
|
||||||
|
node.value = value;
|
||||||
|
freqInc(node);
|
||||||
|
} else {
|
||||||
|
if (size == capacity) {
|
||||||
|
//如果已经等于了就要进行删除
|
||||||
|
removeNode();
|
||||||
|
|
||||||
|
}
|
||||||
|
Node node1 = new Node(key, value, 1);
|
||||||
|
cache.put(key, node1);
|
||||||
|
addNode(node1);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void freqInc(Node node) {
|
||||||
|
int freq = node.freq;
|
||||||
|
NodeList nodeList = freqMap.get(freq);
|
||||||
|
if (nodeList != null) {
|
||||||
|
nodeList.removeNode(node);
|
||||||
|
} else {
|
||||||
|
nodeList = new NodeList();
|
||||||
|
freqMap.put(freq, nodeList);
|
||||||
|
}
|
||||||
|
if (freq == min && nodeList.isEmpty()) {
|
||||||
|
min = freq + 1;
|
||||||
|
}
|
||||||
|
node.freq++;
|
||||||
|
NodeList nodeList1 = freqMap.get(freq + 1);
|
||||||
|
if (nodeList1 == null) {
|
||||||
|
nodeList1 = new NodeList();
|
||||||
|
freqMap.put(freq + 1, nodeList1);
|
||||||
|
}
|
||||||
|
nodeList1.addNode(node);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNode(Node node) {
|
||||||
|
int freq = node.freq;
|
||||||
|
NodeList nodeList = freqMap.get(freq);
|
||||||
|
if (nodeList == null) {
|
||||||
|
nodeList = new NodeList();
|
||||||
|
freqMap.put(freq, nodeList);
|
||||||
|
}
|
||||||
|
nodeList.addNode(node);
|
||||||
|
min = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeNode() {
|
||||||
|
NodeList nodeList = freqMap.get(min);
|
||||||
|
|
||||||
|
Node node = nodeList.removeNode();
|
||||||
|
cache.remove(node.key);
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
T55_LFUCache lRUCache = new T55_LFUCache(2);
|
||||||
|
lRUCache.put(1, 1); // 缓存是 {1=1}
|
||||||
|
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
|
||||||
|
System.out.println(lRUCache.get(1)); // 返回 1
|
||||||
|
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
|
||||||
|
System.out.println(lRUCache.get(2)); // 返回 -1 (未找到)
|
||||||
|
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
|
||||||
|
System.out.println(lRUCache.get(1)); // 返回 -1 (未找到)
|
||||||
|
System.out.println(lRUCache.get(3)); // 返回 3
|
||||||
|
System.out.println(lRUCache.get(4)); // 返回 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Node {
|
||||||
|
|
||||||
|
int key;
|
||||||
|
int value;
|
||||||
|
int freq;
|
||||||
|
Node pre;
|
||||||
|
Node next;
|
||||||
|
|
||||||
|
|
||||||
|
public Node() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(int key, int value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
this.freq = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(int key, int value, int freq) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
this.freq = freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(int key, int value, int freq, Node pre, Node next) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
this.freq = freq;
|
||||||
|
this.pre = pre;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class NodeList {
|
||||||
|
|
||||||
|
Node head;
|
||||||
|
Node tail;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
public NodeList() {
|
||||||
|
head = new Node();
|
||||||
|
tail = new Node();
|
||||||
|
head.next = tail;
|
||||||
|
tail.pre = head;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//移除链表中的最后一个节点
|
||||||
|
public Node removeNode() {
|
||||||
|
return removeNode(tail.pre);
|
||||||
|
}
|
||||||
|
|
||||||
|
//移除链表指定元素
|
||||||
|
public Node removeNode(Node node) {
|
||||||
|
node.pre.next = node.next;
|
||||||
|
node.next.pre = node.pre;
|
||||||
|
size--;
|
||||||
|
return node;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//加在链表中第一个位置
|
||||||
|
public void addNode(Node node) {
|
||||||
|
node.next = head.next;
|
||||||
|
head.next.pre = node;
|
||||||
|
head.next = node;
|
||||||
|
node.pre = head;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
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-30 10:14
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣300 最长递增子序列:
|
||||||
|
* 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
|
||||||
|
* 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T78_LengthOfLIS {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
// int[] nums={10,9,2,5,3,7,101,18};
|
||||||
|
int[] nums = {1, 3, 6, 7, 9, 4, 10, 5, 6};
|
||||||
|
System.out.println(lengthOfLIS(nums));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:dp
|
||||||
|
* dp[i]表示以0开头以i结尾的数组的最长递增子序列长度
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int lengthOfLIS(int[] nums) {
|
||||||
|
|
||||||
|
int[] dp = new int[nums.length];
|
||||||
|
Arrays.fill(dp, 1);
|
||||||
|
int max = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 1; i < dp.length; i++) {
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
if (nums[i] > nums[j]) {
|
||||||
|
dp[i] = Math.max(dp[i], dp[j] + 1);
|
||||||
|
}
|
||||||
|
if (max < dp[i]) max = dp[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int lengthOfLIS1(int[] nums) {
|
||||||
|
int N = nums.length;
|
||||||
|
//end[i]表示i+1长度的递增子序列的最小值
|
||||||
|
int[] end = new int[N];
|
||||||
|
end[0] = nums[0];
|
||||||
|
int index = 0;
|
||||||
|
for(int i=1; i< N;i++){
|
||||||
|
if(nums[i] > end[index]){
|
||||||
|
end[++index] = nums[i];
|
||||||
|
} else {
|
||||||
|
for (int j = 0; j <= index; j++) {
|
||||||
|
if (nums[i] <= end[j]) {
|
||||||
|
end[j] = nums[i];//替换对应的位置
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,241 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-03-30 10:36
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣301 删除无效的括号:
|
||||||
|
* 给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
|
||||||
|
* 返回所有可能的结果。答案可以按 任意顺序 返回。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T79_RemoveInvalidParentheses {
|
||||||
|
|
||||||
|
|
||||||
|
//不知道该怎么去重,就用set存储结果 18ms
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
StringBuilder str;
|
||||||
|
|
||||||
|
public List<String> removeInvalidParentheses(String s) {
|
||||||
|
int lmove = 0;
|
||||||
|
int rmove = 0;
|
||||||
|
str = new StringBuilder(s);
|
||||||
|
//遍历一遍,求出要删除左括号和右括号的数量
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
if (s.charAt(i) == '(') {
|
||||||
|
lmove++;
|
||||||
|
} else if (s.charAt(i) == ')') {
|
||||||
|
//左右括号可以匹配
|
||||||
|
if (lmove > 0) {
|
||||||
|
lmove--;
|
||||||
|
} else {
|
||||||
|
rmove++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dfs(lmove, rmove, 0);
|
||||||
|
return new ArrayList<>(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dfs(int lmove, int rmove, int i) {
|
||||||
|
if (lmove == 0 && rmove == 0) {
|
||||||
|
//判断字符串内括号是否有效
|
||||||
|
if (isValid(str)) {
|
||||||
|
set.add(new String(str.toString()));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//还需要删除的括号个数 小于 能过删除的字符个数
|
||||||
|
if (lmove + rmove > str.length() - i) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//不删除
|
||||||
|
dfs(lmove, rmove, i + 1);
|
||||||
|
|
||||||
|
//删除,分左右括号考虑
|
||||||
|
if (str.charAt(i) == '(' && lmove > 0) {
|
||||||
|
str.deleteCharAt(i);//删除
|
||||||
|
dfs(lmove - 1, rmove, i);//进入下一层,因为删除了i处括号,所以不需要i+1
|
||||||
|
str.insert(i, '(');//恢复现场
|
||||||
|
} else if (str.charAt(i) == ')' && rmove > 0) {
|
||||||
|
str.deleteCharAt(i);//删除
|
||||||
|
dfs(lmove, rmove - 1, i);//进入下一层
|
||||||
|
str.insert(i, ')');//恢复现场
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid(StringBuilder str) {
|
||||||
|
int left = 0;
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
if (str.charAt(i) == '(') {
|
||||||
|
left++;
|
||||||
|
} else if (str.charAt(i) == ')') {
|
||||||
|
left--;
|
||||||
|
}
|
||||||
|
if (left < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//自己去重4ms
|
||||||
|
private List<String> res = new ArrayList<String>();
|
||||||
|
|
||||||
|
public List<String> removeInvalidParentheses1(String s) {
|
||||||
|
int lremove = 0;
|
||||||
|
int rremove = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
if (s.charAt(i) == '(') {
|
||||||
|
lremove++;
|
||||||
|
} else if (s.charAt(i) == ')') {
|
||||||
|
if (lremove == 0) {
|
||||||
|
rremove++;
|
||||||
|
} else {
|
||||||
|
lremove--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
helper(s, 0, lremove, rremove);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void helper(String str, int start, int lremove, int rremove) {
|
||||||
|
if (lremove == 0 && rremove == 0) {
|
||||||
|
if (isValid(str)) {
|
||||||
|
res.add(str);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = start; i < str.length(); i++) {
|
||||||
|
if (i != start && str.charAt(i) == str.charAt(i - 1)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 如果剩余的字符无法满足去掉的数量要求,直接返回
|
||||||
|
if (lremove + rremove > str.length() - i) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 尝试去掉一个左括号
|
||||||
|
if (lremove > 0 && str.charAt(i) == '(') {
|
||||||
|
helper(str.substring(0, i) + str.substring(i + 1), i, lremove - 1, rremove);
|
||||||
|
}
|
||||||
|
// 尝试去掉一个右括号
|
||||||
|
if (rremove > 0 && str.charAt(i) == ')') {
|
||||||
|
helper(str.substring(0, i) + str.substring(i + 1), i, lremove, rremove - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValid(String str) {
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
if (str.charAt(i) == '(') {
|
||||||
|
cnt++;
|
||||||
|
} else if (str.charAt(i) == ')') {
|
||||||
|
cnt--;
|
||||||
|
if (cnt < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
String s ="()())()";
|
||||||
|
System.out.println(removeInvalidParentheses2(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//自己尝试一遍
|
||||||
|
public List<String> removeInvalidParentheses2(String s) {
|
||||||
|
|
||||||
|
//统计需要去掉的左括号和右括号的数量
|
||||||
|
|
||||||
|
int left = 0;
|
||||||
|
int right = 0;
|
||||||
|
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
if (c == '(') {
|
||||||
|
left++;
|
||||||
|
} else if (c == ')') {
|
||||||
|
if (left == 0) {
|
||||||
|
right++;
|
||||||
|
} else {
|
||||||
|
left--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
helper1(s, left, right, 0);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void helper1(String s, int left, int right, int start) {
|
||||||
|
if (left == 0 && right == 0) {
|
||||||
|
if (isValid1(s)) {
|
||||||
|
res.add(s);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = start; i < s.length(); i++) {
|
||||||
|
//去重
|
||||||
|
if (i != start && s.charAt(i) == s.charAt(i - 1)) continue;
|
||||||
|
|
||||||
|
if (left + right > s.length() - i) {
|
||||||
|
//怎么删都不够了
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//尝试删除左括号
|
||||||
|
if (left > 0 && s.charAt(i) == '(') {
|
||||||
|
helper1(s.substring(0, i) + s.substring(i + 1), left - 1, right, i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//尝试删除右括号
|
||||||
|
if (right > 0 && s.charAt(i) == ')') {
|
||||||
|
helper1(s.substring(0, i) + s.substring(i + 1), left, right - 1, i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid1(String s) {
|
||||||
|
int left = 0;
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
if (c == '(') {
|
||||||
|
left++;
|
||||||
|
} else if (c == ')') {
|
||||||
|
if (left == 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
left--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return left==0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-03-31 11:13
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣309 最佳买卖股票时机含冷冻期:
|
||||||
|
* 给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。
|
||||||
|
* 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
|
||||||
|
* 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
|
||||||
|
* 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T80_MaxProfit {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] prices = {1, 2, 3, 0, 2};
|
||||||
|
System.out.println(maxProfit(prices));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态dp,状态分为三种:
|
||||||
|
* 今天手里没有股票且不在冷冻期dp[i][0]
|
||||||
|
* 今天手里没有股票且在冷冻期dp[i][1]
|
||||||
|
* 今天手里有股票dp[i][2]
|
||||||
|
* @param prices
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit(int[] prices) {
|
||||||
|
if (prices.length == 1) return 0;
|
||||||
|
|
||||||
|
int[][] dp = new int[prices.length][3];
|
||||||
|
|
||||||
|
dp[0][0] = 0;
|
||||||
|
dp[0][1] = 0;
|
||||||
|
dp[0][2] = -prices[0];
|
||||||
|
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);//昨天是冷冻期;或者昨天也没买
|
||||||
|
dp[i][1] = dp[i - 1][2] + prices[i];//必须是今天买入
|
||||||
|
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][0] - prices[i]);//必须是今天买入
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.max(dp[dp.length - 1][0], dp[dp.length - 1][1]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//滚动数组优化
|
||||||
|
public int maxProfit1(int[] prices) {
|
||||||
|
if (prices.length == 1) return 0;
|
||||||
|
|
||||||
|
|
||||||
|
int dp0 = 0;
|
||||||
|
int dp1 = 0;
|
||||||
|
int dp2 = -prices[0];
|
||||||
|
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
int temp = dp0;
|
||||||
|
dp0 = Math.max(dp0, dp1);//昨天是冷冻期;或者昨天也没买
|
||||||
|
dp1 = dp2 + prices[i];//必须是今天买入
|
||||||
|
dp2 = Math.max(dp2, temp - prices[i]);//必须是今天买入
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.max(dp0, dp1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-03-31 11:28
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣312 戳气球:
|
||||||
|
* 有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
|
||||||
|
* 现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。
|
||||||
|
* 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。
|
||||||
|
* 求所能获得硬币的最大数量。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T81_MaxCoins {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] nums = {3, 1, 5, 8};
|
||||||
|
System.out.println(maxCoins1(nums));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:优先戳中间最小的
|
||||||
|
* 不对
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxCoins(int[] nums) {
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
int count = nums.length;
|
||||||
|
|
||||||
|
while (nums[0] != -1) {
|
||||||
|
int minIndex = 0;
|
||||||
|
int threshold = nums.length;
|
||||||
|
|
||||||
|
if (count == 3) {
|
||||||
|
boolean flag = false;
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
if (nums[i] == -1) {
|
||||||
|
threshold = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nums[i] == 1) {
|
||||||
|
minIndex = i;
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!flag) {
|
||||||
|
minIndex = 1;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
if (nums[i] == -1) {
|
||||||
|
threshold = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nums[minIndex] > nums[i]) {
|
||||||
|
minIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//戳i位置
|
||||||
|
int left;
|
||||||
|
if (minIndex - 1 < 0) {
|
||||||
|
left = 1;
|
||||||
|
} else {
|
||||||
|
left = nums[minIndex - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int right;
|
||||||
|
if (minIndex + 1 >= threshold) {
|
||||||
|
right = 1;
|
||||||
|
} else {
|
||||||
|
right = nums[minIndex + 1];
|
||||||
|
}
|
||||||
|
result += left * nums[minIndex] * right;
|
||||||
|
System.arraycopy(nums, minIndex + 1, nums, minIndex, threshold - minIndex - 1);
|
||||||
|
nums[threshold - 1] = -1;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方动态规划法:
|
||||||
|
* dp[i][j]表示填满开区间(i,j)能得到的最多硬币数
|
||||||
|
* 最终答案即为 dp[0][n+1]dp[0][n+1]dp[0][n+1]。实现时要注意到动态规划的次序。
|
||||||
|
* 动态规划:
|
||||||
|
* 速度击败27.13% 内存击败45.56% 43ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxCoins1(int[] nums) {
|
||||||
|
int n = nums.length;
|
||||||
|
int[][] rec = new int[n + 2][n + 2];
|
||||||
|
int[] val = new int[n + 2];
|
||||||
|
val[0] = val[n + 1] = 1;
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
val[i] = nums[i - 1];
|
||||||
|
}
|
||||||
|
for (int i = n - 1; i >= 0; i--) {
|
||||||
|
for (int j = i + 2; j <= n + 1; j++) {
|
||||||
|
for (int k = i + 1; k < j; k++) {
|
||||||
|
int sum = val[i] * val[k] * val[j];//计算戳当前点的sum
|
||||||
|
sum += rec[i][k] + rec[k][j];//计算不要这个点之后的左右点的戳开的和
|
||||||
|
rec[i][j] = Math.max(rec[i][j], sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rec[0][n + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-03 09:49
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣322 零钱兑换:
|
||||||
|
* 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
|
||||||
|
* 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
|
||||||
|
* 你可以认为每种硬币的数量是无限的。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T82_CoinChange {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] coins = {186, 419, 83, 408};
|
||||||
|
int amount = 6249;
|
||||||
|
System.out.println(coinChange(coins, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:硬币可以使用无数次 完全背包
|
||||||
|
* 动态DP
|
||||||
|
* @param coins
|
||||||
|
* @param amount
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int coinChange(int[] coins, int amount) {
|
||||||
|
|
||||||
|
int[][] dp = new int[coins.length][amount + 1];
|
||||||
|
Arrays.sort(coins);
|
||||||
|
dp[0][0] = 0;
|
||||||
|
for (int i = 1; i < dp[0].length; i++) {
|
||||||
|
if (i >= coins[0] && i % coins[0] == 0) dp[0][i] = dp[0][i - coins[0]] + 1;
|
||||||
|
else dp[0][i] = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < dp.length; i++) {
|
||||||
|
for (int j = 1; j < dp[0].length; j++) {
|
||||||
|
if (j >= coins[i] && dp[i][j - coins[i]] != Integer.MAX_VALUE) {
|
||||||
|
dp[i][j] = Math.min(dp[i][j - coins[i]] + 1, dp[i - 1][j]);
|
||||||
|
} else dp[i][j] = dp[i - 1][j];//使用哪一个
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[coins.length - 1][amount] == Integer.MAX_VALUE ? -1 : dp[coins.length - 1][amount];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一维dp优化
|
||||||
|
* @param coins
|
||||||
|
* @param amount
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int coinChange1(int[] coins, int amount) {
|
||||||
|
|
||||||
|
int[] dp = new int[amount + 1];
|
||||||
|
// Arrays.sort(coins);
|
||||||
|
dp[0] = 0;
|
||||||
|
for (int i = 1; i < dp.length; i++) {
|
||||||
|
if (i >= coins[0] && i % coins[0] == 0) dp[i] = dp[i - coins[0]] + 1;
|
||||||
|
else dp[i] = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < coins.length; i++) {
|
||||||
|
for (int j = coins[i]; j < dp.length; j++) {
|
||||||
|
if (j >= coins[i] && dp[j - coins[i]] != Integer.MAX_VALUE) {
|
||||||
|
dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-03 10:24
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣337 打家劫舍III:
|
||||||
|
* 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
|
||||||
|
* 除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。
|
||||||
|
* 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
|
||||||
|
* 给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T83_Rob {
|
||||||
|
|
||||||
|
public int rob(TreeNode root) {
|
||||||
|
|
||||||
|
int[] dp = subRob(root);
|
||||||
|
return Math.max(dp[0],dp[1]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] subRob(TreeNode root) {
|
||||||
|
if (root == null) {
|
||||||
|
return new int[]{0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] left = subRob(root.left);
|
||||||
|
int[] right = subRob(root.right);
|
||||||
|
|
||||||
|
int steal = left[0] + right[0] + root.val;
|
||||||
|
int noSteal = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
|
||||||
|
|
||||||
|
return new int[]{noSteal, steal};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-03 10:38
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣338 比特位计数:
|
||||||
|
* 给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T84_CountBits {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
int n = 85723;
|
||||||
|
System.out.println(Arrays.toString(countBits(n)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*思路:挨个增加,有则进位
|
||||||
|
* 速度击败6.9% 内存击败13.58% 59ms
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[] countBits(int n) {
|
||||||
|
|
||||||
|
int[] nums = new int[n + 1];
|
||||||
|
long cur = 0;
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
long[] check = check(cur);
|
||||||
|
cur = check[0] + 1;
|
||||||
|
nums[i] = (int)check[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nums;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int num = 1112;
|
||||||
|
System.out.println(check(num));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long[] check(long n) {
|
||||||
|
//int count =0;
|
||||||
|
boolean flag = false;//是否进位
|
||||||
|
int num = 0;
|
||||||
|
int count = 0;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (n != 0 || flag) {
|
||||||
|
long cur = n % 10;
|
||||||
|
if (flag) cur += 1;
|
||||||
|
if (cur == 1) count++;
|
||||||
|
if (cur > 1) {
|
||||||
|
flag = true;
|
||||||
|
sb.append(0);
|
||||||
|
} else {
|
||||||
|
flag = false;
|
||||||
|
sb.append(cur);
|
||||||
|
}
|
||||||
|
n /= 10;
|
||||||
|
}
|
||||||
|
if (sb.length() == 0) {
|
||||||
|
sb.append(0);
|
||||||
|
}
|
||||||
|
return new long[]{Long.parseLong(sb.reverse().toString()), count};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方题解:Brian Kernighan 算法
|
||||||
|
* x=x & (x−1) 这一运算将x的二进制表示的最后一个1变成0
|
||||||
|
* 因此重复该操作,直到x变成0,就可以得到x中1的数量
|
||||||
|
* 速度击败41.7% 内存击败28.3% 2ms
|
||||||
|
* 时间复杂度O(nlogn)
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[] countBits1(int n) {
|
||||||
|
int[] bits = new int[n + 1];
|
||||||
|
for (int i = 0; i <= n; i++) {
|
||||||
|
bits[i] = countOnes(i);
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countOnes(int x) {
|
||||||
|
int ones = 0;
|
||||||
|
while (x > 0) {
|
||||||
|
x &= (x - 1);
|
||||||
|
ones++;
|
||||||
|
}
|
||||||
|
return ones;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方题解:动态规划法:最低位有效值
|
||||||
|
* 即如果x为偶数,bit[x]=bit[x/2]
|
||||||
|
* 如果x为奇数,bit[x]=bit[x/2]+1
|
||||||
|
* 是否加1可以使用对2取余:x 除以 2的余数可以通过 x & 1 得到
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[] countBits2(int n) {
|
||||||
|
int[] bits = new int[n + 1];
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
bits[i] = bits[i >> 1] + (i & 1);
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-03 11:37
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣347 前k个高频元素:
|
||||||
|
* 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T85_TopKFrequent {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
int[] nums={4,1,-1,2,-1,2,3};
|
||||||
|
System.out.println(topKFrequent(nums,2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计每个单词出现的次数,然后进行堆化
|
||||||
|
* 速度击败87.71% 内存击败12.19% 12ms
|
||||||
|
* @param nums
|
||||||
|
* @param k
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[] topKFrequent(int[] nums, int k) {
|
||||||
|
|
||||||
|
Map<Integer, Integer> map = new HashMap<>();//<nums,count>
|
||||||
|
for (int num : nums) {
|
||||||
|
map.put(num, map.getOrDefault(num, 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
|
||||||
|
@Override
|
||||||
|
public int compare(int[] o1, int[] o2) {
|
||||||
|
return o1[0] != o2[0] ? o2[1] - o1[1] : o2[0] - o1[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
|
||||||
|
queue.add(new int[]{entry.getKey(), entry.getValue()});
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] result = new int[k];
|
||||||
|
|
||||||
|
for (int i = 0; i < k; i++) {
|
||||||
|
if(!queue.isEmpty()) result[i] = queue.poll()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方最快:先计算每个数字出现的次数,使用arrayList将相同次数的数字放在一次
|
||||||
|
* @param nums
|
||||||
|
* @param k
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[] topKFrequent1(int[] nums, int k) {
|
||||||
|
int max = Integer.MIN_VALUE,min = Integer.MAX_VALUE;
|
||||||
|
for(int i : nums){//找出最大最小值
|
||||||
|
max = (max < i)?i:max;
|
||||||
|
min = (min > i)?i:min;
|
||||||
|
}
|
||||||
|
if(max==min)return new int[]{nums[0]};
|
||||||
|
int times[] = new int[max-min+1];//定义桶大小
|
||||||
|
for(int i : nums){
|
||||||
|
times[i-min]++;//记录各个数出现的次数
|
||||||
|
}
|
||||||
|
ArrayList<Integer> count[] = new ArrayList[nums.length];//不同数量对应的数字集合
|
||||||
|
for(int i = 0; i < times.length; i++){
|
||||||
|
if(times[i] > 0){
|
||||||
|
if(count[times[i]] == null){
|
||||||
|
count[times[i]] = new ArrayList();
|
||||||
|
}
|
||||||
|
count[times[i]].add(i+min);//相同次数的加在同一个count[i]这种
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int res[] = new int[k];//答案
|
||||||
|
for(int i = count.length-1,j = 0; i >=0 && j < k ; i--){
|
||||||
|
if(count[i] != null){
|
||||||
|
while(!count[i].isEmpty()){
|
||||||
|
res[j++] = count[i].remove(count[i].size()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-06 10:04
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣394 字符串解码:
|
||||||
|
* 给定一个经过编码的字符串,返回它解码后的字符串。
|
||||||
|
* 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
|
||||||
|
* 你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
|
||||||
|
* 此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T86_DecodeString {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
String s = "3[a]2[bc]";
|
||||||
|
System.out.println(decodeString(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
String s = "3[a2[c]]";
|
||||||
|
System.out.println(decodeString(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
String s = "3[z]2[2[y]pq4[2[jk]e1[f]]]ef";
|
||||||
|
System.out.println(decodeString(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public String decodeString(String s) {
|
||||||
|
return decodeSubString(s.toCharArray(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String decodeSubString(char[] chars, int count) {
|
||||||
|
if (chars[start] == '[') start++;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int sum = 0;
|
||||||
|
while (start < chars.length && Character.isDigit(chars[start])) {
|
||||||
|
sum = sum * 10 + (chars[start] - '0');
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
//如果前面没有数字,返回1次
|
||||||
|
if (sum == 0) {
|
||||||
|
while (start < chars.length && chars[start] >= 'a' && chars[start] <= 'z') {
|
||||||
|
sb.append(chars[start++]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sb.append(decodeSubString(chars, sum));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (start < chars.length && Character.isDigit(chars[start])) {
|
||||||
|
// sb.append(decodeSubString(chars, 1));
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (start < chars.length && chars[start] == ']') {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
if (count > 1) {
|
||||||
|
String k = sb.toString();
|
||||||
|
for (int i = 0; i < count - 1; i++) {
|
||||||
|
sb.append(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start < chars.length && chars[start] != ']') {
|
||||||
|
sb.append(decodeSubString(chars, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String src;
|
||||||
|
int ptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方递归法:
|
||||||
|
* 思路和本人一致,但是思路更清晰和简洁
|
||||||
|
* 速度击败100% 内存击败76.28%
|
||||||
|
* @param s
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String decodeString1(String s) {
|
||||||
|
src = s;
|
||||||
|
ptr = 0;
|
||||||
|
return getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() {
|
||||||
|
if (ptr == src.length() || src.charAt(ptr) == ']') {
|
||||||
|
// String -> EPS
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
char cur = src.charAt(ptr);
|
||||||
|
int repTime = 1;
|
||||||
|
StringBuilder ret = new StringBuilder();
|
||||||
|
|
||||||
|
if (Character.isDigit(cur)) {
|
||||||
|
// String -> Digits [ String ] String
|
||||||
|
// 解析 Digits
|
||||||
|
repTime = getDigits();
|
||||||
|
// 过滤左括号
|
||||||
|
++ptr;
|
||||||
|
// 解析 String
|
||||||
|
String str = getString();
|
||||||
|
// 过滤右括号
|
||||||
|
++ptr;
|
||||||
|
// 构造字符串
|
||||||
|
while (repTime-- > 0) {
|
||||||
|
ret.append(str);
|
||||||
|
}
|
||||||
|
} else if (Character.isLetter(cur)) {
|
||||||
|
// String -> Char String
|
||||||
|
// 解析 Char
|
||||||
|
ret.append(String.valueOf(src.charAt(ptr++)));
|
||||||
|
}
|
||||||
|
ret.append(getString());
|
||||||
|
|
||||||
|
return ret.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDigits() {
|
||||||
|
int ret = 0;
|
||||||
|
while (ptr < src.length() && Character.isDigit(src.charAt(ptr))) {
|
||||||
|
ret = ret * 10 + src.charAt(ptr++) - '0';
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-06 11:47
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣399 除法求值:
|
||||||
|
* 给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。
|
||||||
|
* 另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。
|
||||||
|
* 返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。
|
||||||
|
* 注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T87_CalcEquation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方题解:并查集解法
|
||||||
|
* 速度击败100% 内存击败85.81% 0ms
|
||||||
|
* @param equations
|
||||||
|
* @param values
|
||||||
|
* @param queries
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
|
||||||
|
|
||||||
|
int equationSize = equations.size();
|
||||||
|
UnionFind unionFind = new UnionFind(2 * equationSize);
|
||||||
|
//第一步:预处理,将变量的值与id进行映射,是的并查集的底层使用数组实现,方便编码
|
||||||
|
HashMap<String, Integer> hashMap = new HashMap<>(2 * equationSize);
|
||||||
|
int id = 0;
|
||||||
|
for (int i = 0; i < equationSize; i++) {
|
||||||
|
List<String> equation = equations.get(i);
|
||||||
|
String var1 = equation.get(0);
|
||||||
|
String var2 = equation.get(1);
|
||||||
|
if (!hashMap.containsKey(var1)) {
|
||||||
|
hashMap.put(var1, id);
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
if (!hashMap.containsKey(var2)) {
|
||||||
|
hashMap.put(var2, id);
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
unionFind.union(hashMap.get(var1), hashMap.get(var2), values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//第二部:做查询
|
||||||
|
int queriesSize = queries.size();
|
||||||
|
double[] res = new double[queriesSize];
|
||||||
|
for (int i = 0; i < queriesSize; i++) {
|
||||||
|
String var1 = queries.get(i).get(0);
|
||||||
|
String var2 = queries.get(i).get(1);
|
||||||
|
Integer id1 = hashMap.get(var1);
|
||||||
|
Integer id2 = hashMap.get(var2);
|
||||||
|
if (id1 == null || id2 == null) {
|
||||||
|
res[i] = -1.0d;
|
||||||
|
} else {
|
||||||
|
res[i] = unionFind.isConnected(id1, id2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class UnionFind {
|
||||||
|
|
||||||
|
private int[] parent;
|
||||||
|
|
||||||
|
private double[] weight;
|
||||||
|
|
||||||
|
public UnionFind(int n) {
|
||||||
|
this.parent = new int[n];
|
||||||
|
this.weight = new double[n];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
parent[i] = i;
|
||||||
|
weight[i] = 1.0d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void union(int x, int y, double value) {
|
||||||
|
int rootX = find(x);
|
||||||
|
int rootY = find(y);
|
||||||
|
if (rootX == rootY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parent[rootX] = rootY;
|
||||||
|
weight[rootX] = weight[y] * value / weight[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 路径压缩
|
||||||
|
* @param x
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private int find(int x) {
|
||||||
|
if (x != parent[x]) {//存在引用链,至少是第一次遍历到才会不相等
|
||||||
|
int origin = parent[x];
|
||||||
|
parent[x] = find(parent[x]);
|
||||||
|
weight[x] *= weight[origin];
|
||||||
|
}
|
||||||
|
return parent[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
public double isConnected(int x, int y) {
|
||||||
|
int rootX = find(x);
|
||||||
|
int rootY = find(y);
|
||||||
|
if (rootY == rootX) {
|
||||||
|
return weight[x] / weight[y];
|
||||||
|
} else {
|
||||||
|
return -1.0d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方DFS法:本质上就是把数据加入子集当中,然后如果存在引用链就一定能够被连接上,则可以计算
|
||||||
|
* 速度击败54.5% 内存击败29.67% 1ms
|
||||||
|
* @param equations
|
||||||
|
* @param values
|
||||||
|
* @param queries
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public double[] calcEquation1(List<List<String>> equations, double[] values, List<List<String>> queries) {
|
||||||
|
double[] result = new double[queries.size()];
|
||||||
|
Map<String, Map<String, Double>> graph = buildGraph(equations, values);
|
||||||
|
|
||||||
|
for (int i = 0; i < queries.size(); i++) {
|
||||||
|
//dfs寻找对应的引用
|
||||||
|
String start = queries.get(i).get(0);
|
||||||
|
String end = queries.get(i).get(1);
|
||||||
|
|
||||||
|
if (!graph.containsKey(start) || !graph.containsKey(end)) {
|
||||||
|
result[i] = -1;//有一个没有就肯定计算不出来
|
||||||
|
} else {
|
||||||
|
Set<String> visited = new HashSet<>();
|
||||||
|
result[i] = dfs(graph, start, end, visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建引用链
|
||||||
|
private Map<String, Map<String, Double>> buildGraph(List<List<String>> equations, double[] values) {
|
||||||
|
Map<String, Map<String, Double>> graph = new HashMap<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < equations.size(); i++) {
|
||||||
|
String v1 = equations.get(i).get(0);
|
||||||
|
String v2 = equations.get(i).get(1);
|
||||||
|
graph.putIfAbsent(v1, new HashMap<String, Double>());
|
||||||
|
graph.get(v1).put(v2, values[i]);
|
||||||
|
|
||||||
|
graph.putIfAbsent(v2, new HashMap<String, Double>());
|
||||||
|
graph.get(v2).put(v1, 1.0 / values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double dfs(Map<String, Map<String, Double>> graph, String start, String end, Set<String> visited) {
|
||||||
|
visited.add(start);
|
||||||
|
Map<String, Double> next = graph.get(start);
|
||||||
|
for (Map.Entry<String, Double> entry : next.entrySet()) {
|
||||||
|
if (entry.getKey().equals(end)) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
if (!visited.contains(entry.getKey())) {
|
||||||
|
double nextValue = dfs(graph, entry.getKey(), end, visited);
|
||||||
|
if (nextValue > 0) {//即不可能是-1就正常返回
|
||||||
|
return entry.getValue() * nextValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-07 10:18
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣406 根据身高重建队列:
|
||||||
|
* 假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。
|
||||||
|
* 每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
|
||||||
|
* 请你重新构造并返回输入数组 people 所表示的队列。
|
||||||
|
* 返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T88_ReconstructQueue {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[][] people = {{7, 0}, {4, 4}, {7, 1}, {5, 0}, {6, 1}, {5, 2}};
|
||||||
|
// reconstructQueue1(people);
|
||||||
|
for (int[] ints : reconstructQueue1(people)) {
|
||||||
|
System.out.println(Arrays.toString(ints));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:排序后使用linkedList插入
|
||||||
|
* 速度击败26.34% 内存击败70.6% 9ms
|
||||||
|
* @param people
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[][] reconstructQueue(int[][] people) {
|
||||||
|
|
||||||
|
Arrays.sort(people, new Comparator<int[]>() {
|
||||||
|
@Override
|
||||||
|
public int compare(int[] o1, int[] o2) {
|
||||||
|
return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
LinkedList<int[]> list = new LinkedList<>();
|
||||||
|
|
||||||
|
for (int[] person : people) {
|
||||||
|
list.add(person[1], person);
|
||||||
|
}
|
||||||
|
int[][] result = new int[people.length][];
|
||||||
|
|
||||||
|
|
||||||
|
return list.toArray(new int[people.length][]);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 先排序后腾挪
|
||||||
|
* 速度击败81.31% 内存击败17.3% 6ms
|
||||||
|
* @param people
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[][] reconstructQueue1(int[][] people) {
|
||||||
|
|
||||||
|
Arrays.sort(people, new Comparator<int[]>() {
|
||||||
|
@Override
|
||||||
|
public int compare(int[] o1, int[] o2) {
|
||||||
|
return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = people.length - 1; i >= 0; i--) {
|
||||||
|
int[] person = people[i];
|
||||||
|
|
||||||
|
//看看前面有几个和他相等的
|
||||||
|
int same = 0;
|
||||||
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
|
if (people[j][0] == person[0]) same++;
|
||||||
|
if (people[j][0] < person[0]) break;//小了直接break
|
||||||
|
}
|
||||||
|
//不相等,需要腾挪
|
||||||
|
if (same != person[1]) {
|
||||||
|
int length = person[1] - same;
|
||||||
|
System.arraycopy(people, i + 1, people, i, length);
|
||||||
|
people[i + length] = person;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return people;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-07 10:52
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣416 分割等和数组:
|
||||||
|
* 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T89_CanPartition {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
// int[] nums={1,5,11,5};
|
||||||
|
int[] nums = {1, 2, 3, 5};
|
||||||
|
System.out.println(canPartition(nums));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:本质上就是找一个总和一半的子序列
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean canPartition(int[] nums) {
|
||||||
|
|
||||||
|
if (nums.length < 2) return false;
|
||||||
|
int sum = 0;
|
||||||
|
int max = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
sum += num;
|
||||||
|
max = Math.max(max, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum % 2 != 0) return false;
|
||||||
|
int target = sum / 2;
|
||||||
|
if (max > target) return false;
|
||||||
|
boolean[] dp = new boolean[target + 1];
|
||||||
|
dp[0]=true;
|
||||||
|
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
for (int j = dp.length - 1; j >= nums[i]; j--) {
|
||||||
|
dp[j] |= dp[j - nums[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[target];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
import com.markilue.leecode.tree.TreeUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-07 11:05
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣437 路径总和III:
|
||||||
|
* 给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
|
||||||
|
* 路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T90_PathSum {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
TreeNode root = TreeUtils.structureTree(new ArrayList<>(Arrays.asList(10, 5, -3, 3, 2, null, 11, 3, -2, null, 1)), 0);
|
||||||
|
System.out.println(pathSum(root, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:可以把return的状态分为 不要之前的左 不要之前右 都不要
|
||||||
|
* 有问题:节点的始末不一定是终点
|
||||||
|
* @param root
|
||||||
|
* @param targetSum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int pathSum(TreeNode root, int targetSum) {
|
||||||
|
cur.add(0);
|
||||||
|
path(root, targetSum, 0);
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
List<Integer> cur = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
public void path(TreeNode root, int targetSum, int last) {
|
||||||
|
if (root == null) return;
|
||||||
|
int value = root.val;
|
||||||
|
for (Integer integer : cur) {
|
||||||
|
if (integer + value == targetSum) sum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sum = value + last;
|
||||||
|
cur.add(value);
|
||||||
|
cur.add(sum);
|
||||||
|
|
||||||
|
path(root.left, targetSum, sum);
|
||||||
|
cur.remove(cur.size() - 1);
|
||||||
|
path(root.right, targetSum, sum);
|
||||||
|
cur.remove(cur.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分别计算节点为根的,和他为路径的之和
|
||||||
|
* 时间复杂度为O(N^2)
|
||||||
|
* 速度击败8.17% 内存击败46.54%
|
||||||
|
* @param root
|
||||||
|
* @param targetSum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int pathSum1(TreeNode root, int targetSum) {
|
||||||
|
if (root == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = rootSum(root, targetSum);//计算他为根的
|
||||||
|
ret += pathSum1(root.left, targetSum);//计算不要他的 为路径的
|
||||||
|
ret += pathSum1(root.right, targetSum);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int rootSum(TreeNode root, int targetSum) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (root == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int val = root.val;
|
||||||
|
if (val == targetSum) {
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += rootSum(root.left, targetSum - val);
|
||||||
|
ret += rootSum(root.right, targetSum - val);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方前缀和解法
|
||||||
|
* 时间复杂度O(n)
|
||||||
|
* * 前缀和的递归回溯思路
|
||||||
|
* * 从当前节点反推到根节点(反推比较好理解,正向其实也只有一条),有且仅有一条路径,因为这是一棵树
|
||||||
|
* * 如果此前有和为currSum-target,而当前的和又为currSum,两者的差就肯定为target了
|
||||||
|
* * 所以前缀和对于当前路径来说是唯一的,当前记录的前缀和,在回溯结束,回到本层时去除,保证其不影响其他分支的结果
|
||||||
|
* @param root
|
||||||
|
* @param targetSum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int pathSum2(TreeNode root, int targetSum) {
|
||||||
|
Map<Long, Integer> prefix = new HashMap<Long, Integer>();
|
||||||
|
prefix.put(0L, 1);
|
||||||
|
return dfs(root, prefix, 0, targetSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int dfs(TreeNode root, Map<Long, Integer> prefix, long curr, int targetSum) {
|
||||||
|
if (root == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
curr += root.val;
|
||||||
|
|
||||||
|
//---核心代码
|
||||||
|
//看看root到当前节点这条路上是否存在节点前缀和加target为currSum的路径
|
||||||
|
//当前节点->root节点反推,有且仅有一条路径,如果此前有和为currSum-target,而当前的和又为currSum,两者的差就肯定为target了
|
||||||
|
//currSum-target相当于找路径的起点,起点的sum+target=currSum,当前点到起点的距离就是target
|
||||||
|
|
||||||
|
|
||||||
|
ret = prefix.getOrDefault(curr - targetSum, 0);
|
||||||
|
prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);
|
||||||
|
ret += dfs(root.left, prefix, curr, targetSum);
|
||||||
|
ret += dfs(root.right, prefix, curr, targetSum);
|
||||||
|
prefix.put(curr, prefix.getOrDefault(curr, 0) - 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-08 11:54
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣448 找到所有数组中的消失的数字:
|
||||||
|
* 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T92_FindDisappearedNumbers {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
int[] nums = {4, 3, 2, 7, 8, 2, 3, 1};
|
||||||
|
System.out.println(findDisappearedNumbers(nums));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:记录各个数字出现的次数,为0则没有出现
|
||||||
|
* 速度击败99.36% 内存击败52.21% 3ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<Integer> findDisappearedNumbers(int[] nums) {
|
||||||
|
|
||||||
|
int[] counts = new int[nums.length + 1];
|
||||||
|
|
||||||
|
for (int num : nums) {
|
||||||
|
counts[num]++;
|
||||||
|
}
|
||||||
|
List<Integer> result = new ArrayList<>();
|
||||||
|
for (int i = 1; i < counts.length; i++) {
|
||||||
|
if (counts[i] == 0) result.add(i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方题解:原地+n不影响实际结果
|
||||||
|
* 速度击败99.36% 内存击败26.85% 3ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<Integer> findDisappearedNumbers1(int[] nums) {
|
||||||
|
int n = nums.length;
|
||||||
|
for (int num : nums) {
|
||||||
|
int x = (num - 1) % n;
|
||||||
|
nums[x] += n;
|
||||||
|
}
|
||||||
|
List<Integer> ret = new ArrayList<Integer>();
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if (nums[i] <= n) {
|
||||||
|
ret.add(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-08 13:21
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣461 汉明距离:
|
||||||
|
* 两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。
|
||||||
|
* 给你两个整数 x 和 y,计算并返回它们之间的汉明距离。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T93_HammingDistance {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
// System.out.println(3^1);
|
||||||
|
System.out.println(hammingDistance(1, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:异或之后得到不同位为1的值
|
||||||
|
* 然后num&(num-1)可以消除最后一个为1的值,因此可以统计有几个1
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int hammingDistance(int x, int y) {
|
||||||
|
int result = x ^ y;
|
||||||
|
int count = 0;
|
||||||
|
while (result != 0) {
|
||||||
|
count++;
|
||||||
|
result &= (result - 1);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-10 12:49
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣494 目标和:
|
||||||
|
* 给你一个整数数组 nums 和一个整数 target 。
|
||||||
|
* 向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :
|
||||||
|
* 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
|
||||||
|
* 返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T94_FindTargetSumWays {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
int[] nums = {1, 1, 1, 1, 1};
|
||||||
|
int target = 3;
|
||||||
|
System.out.println(findTargetSumWays(nums, target));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:本质上就是一个背包问题:
|
||||||
|
* add-(sum-add)=target
|
||||||
|
* add=(sum+target)/2
|
||||||
|
* 速度击败94.6% 内存击败50.13% 2ms
|
||||||
|
* @param nums
|
||||||
|
* @param target
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findTargetSumWays(int[] nums, int target) {
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
sum += num;
|
||||||
|
}
|
||||||
|
if ((sum + target) % 2 != 0) return 0;
|
||||||
|
int mid = (sum + target) / 2;
|
||||||
|
if (mid < 0) return 0;
|
||||||
|
int[] dp = new int[mid + 1];
|
||||||
|
dp[0] = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
for (int j = mid; j >= nums[i]; j--) {
|
||||||
|
dp[j] += dp[j - nums[i]];//用这个数,不用这个数
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[mid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-10 13:02
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣538 把二叉搜索树转换为累加树:
|
||||||
|
* 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
|
||||||
|
* 提醒一下,二叉搜索树满足下列约束条件:
|
||||||
|
* 节点的左子树仅包含键 小于 节点键的节点。
|
||||||
|
* 节点的右子树仅包含键 大于 节点键的节点。
|
||||||
|
* 左右子树也必须是二叉搜索树。
|
||||||
|
*@Version: 1.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class T95_ConvertBST {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后续遍历:递归法
|
||||||
|
* 速度击败100% 内存击败85.25% 0ms
|
||||||
|
*/
|
||||||
|
|
||||||
|
public TreeNode convertBST(TreeNode root) {
|
||||||
|
if (root == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
convertBST(root.right);
|
||||||
|
sum += root.val;
|
||||||
|
root.val = sum;
|
||||||
|
convertBST(root.left);
|
||||||
|
return root;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-10 13:17
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣543 二叉树的直径:
|
||||||
|
* 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T96_DiameterOfBinaryTree {
|
||||||
|
|
||||||
|
|
||||||
|
int max = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:就是计算最多一条链路上的节点数目
|
||||||
|
* 速度击败100% 内存击败79.29% 递归法
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int diameterOfBinaryTree(TreeNode root) {
|
||||||
|
sub(root);
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sub(TreeNode root) {
|
||||||
|
if (root == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int left = sub(root.left);
|
||||||
|
int right = sub(root.right);
|
||||||
|
max = Math.max(max, left + right);
|
||||||
|
return Math.max(left, right) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-10 13:28
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣560 合为k的子数组:
|
||||||
|
* 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T97_SubarraySum {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] nums = {100,1,2,3,100,1,2,3,4};
|
||||||
|
System.out.println(subarraySum1(nums, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:滑动窗口法(维护一个窗口内总和为k的窗口)
|
||||||
|
* 有问题:因为数组里面有负数的情况,这个判断就是有问题的
|
||||||
|
* @param nums
|
||||||
|
* @param k
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int subarraySum(int[] nums, int k) {
|
||||||
|
if (nums.length == 1 && nums[0] == k) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
int cur = nums[0];
|
||||||
|
int left = 0;
|
||||||
|
int right = 1;
|
||||||
|
|
||||||
|
while (left <= right && right <= nums.length) {
|
||||||
|
if (cur == k && left != right) {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
if (left == nums.length) break;
|
||||||
|
if (right < nums.length) {
|
||||||
|
cur += nums[right++];
|
||||||
|
} else {
|
||||||
|
cur -= nums[left++];//到终点了,直接缩小窗口
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (left < right && cur > k) {
|
||||||
|
|
||||||
|
cur -= nums[left++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方前缀和+hash优化:
|
||||||
|
* 时间复杂度O(n)
|
||||||
|
* 速度击败53.66% 内存击败29.86% 24ms
|
||||||
|
* @param nums
|
||||||
|
* @param k
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int subarraySum1(int[] nums, int k) {
|
||||||
|
int count = 0, pre = 0;
|
||||||
|
HashMap<Integer, Integer> mp = new HashMap<>();//<pre,count>
|
||||||
|
mp.put(0, 1);
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
pre += nums[i];
|
||||||
|
if (mp.containsKey(pre - k)) {
|
||||||
|
count += mp.get(pre - k);
|
||||||
|
}
|
||||||
|
mp.put(pre, mp.getOrDefault(pre, 0) + 1);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方最快:
|
||||||
|
* 速度击败92.3% 内存击败40.6% 21ms
|
||||||
|
* @param nums
|
||||||
|
* @param k
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int subarraySum2(int[] nums, int k) {
|
||||||
|
HashMap<Integer,Integer> map = new HashMap<>();
|
||||||
|
map.put(0,1);
|
||||||
|
int res = 0;
|
||||||
|
int sum = 0;
|
||||||
|
for(int i = 0;i < nums.length; i++){
|
||||||
|
sum+=nums[i];
|
||||||
|
if(map.containsKey(sum - k)){
|
||||||
|
res+=map.get(sum - k);
|
||||||
|
|
||||||
|
}
|
||||||
|
if(map.containsKey(sum)){
|
||||||
|
map.put(sum,map.get(sum)+1);
|
||||||
|
}else{
|
||||||
|
map.put(sum, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-11 12:47
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣581 最短无序连续子数组:
|
||||||
|
* 给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
|
||||||
|
* 请你找出符合题意的 最短 子数组,并输出它的长度。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T98_FindUnsortedSubarray {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方排序法:
|
||||||
|
* TODO 最短的思路:
|
||||||
|
* 本质上就是考虑把数组分为三段子数组:numsA,numsB,numsC ;当对numsB进行排序,整个数组就会变得有序
|
||||||
|
* 所以要找到最短的numsB,就是找到最大的numsA和numsC的长度之和
|
||||||
|
* 因此将数组排序与原数组对比,找到最长相同的前缀numsA和最长相同的后缀numsC,就可以最短numsB
|
||||||
|
* 时间复杂度O(nlogn)
|
||||||
|
* 时间击败36.47% 内存击败15.19% 6ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findUnsortedSubarray(int[] nums) {
|
||||||
|
if (isSorted(nums)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int[] numsSorted = new int[nums.length];
|
||||||
|
System.arraycopy(nums, 0, numsSorted, 0, nums.length);
|
||||||
|
Arrays.sort(numsSorted);
|
||||||
|
int left = 0;
|
||||||
|
while (nums[left] == numsSorted[left]) {
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
int right = nums.length - 1;
|
||||||
|
while (nums[right] == numsSorted[right]) {
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
return right - left + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSorted(int[] nums) {
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
if (nums[i] < nums[i - 1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一次遍历:对于需要排序的优化:
|
||||||
|
* 时间复杂度O(n)
|
||||||
|
* 速度击败93.39% 内存击败68.96% 1ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findUnsortedSubarray1(int[] nums) {
|
||||||
|
//2,6,4,8,10,9,15
|
||||||
|
//升序开始索引:0,2,5
|
||||||
|
//降序开始索引:1,4
|
||||||
|
int n = nums.length;
|
||||||
|
int maxn = Integer.MIN_VALUE, right = -1;
|
||||||
|
int minn = Integer.MAX_VALUE, left = -1;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
// 因此 从左到右 找最大值 这期间如果有值比最大值还要小 那么这个值就有可能是 中段的右边界
|
||||||
|
//因为升序的时候(左右段) 最大值一直在替换,所以最后一个小 它就是 中段的右边界
|
||||||
|
if (maxn > nums[i]) {
|
||||||
|
right = i;
|
||||||
|
} else {
|
||||||
|
maxn = nums[i];
|
||||||
|
}
|
||||||
|
//因此 从右到左 找最小值 这期间如果有值比最小值还要大 那么这个值就有可能是 中段的左边界
|
||||||
|
//因为降序的时候(左右段) 最小值一直在替换,所以最后一个大 它就是 中段的左边界
|
||||||
|
if (minn < nums[n - i - 1]) {
|
||||||
|
left = n - i - 1;
|
||||||
|
} else {
|
||||||
|
minn = nums[n - i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return right == -1 ? 0 : right - left + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-11 14:27
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣617 合并二叉树:
|
||||||
|
* 给你两棵二叉树: root1 和 root2 。
|
||||||
|
* 想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
|
||||||
|
* 返回合并后的二叉树。
|
||||||
|
* 注意: 合并过程必须从两个树的根节点开始。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T99_MergeTrees {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归法
|
||||||
|
* @param root1
|
||||||
|
* @param root2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
|
||||||
|
if (root1 == null) {
|
||||||
|
return root2;
|
||||||
|
} else if (root2 == null) {
|
||||||
|
return root1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//两者都不等于null
|
||||||
|
TreeNode root = new TreeNode(root1.val + root2.val);
|
||||||
|
root.left = mergeTrees(root1.left, root2.left);
|
||||||
|
root.right = mergeTrees(root1.right, root2.right);
|
||||||
|
return root;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,8 @@ import org.junit.Test;
|
||||||
public class DeleteDuplicatesII {
|
public class DeleteDuplicatesII {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test(){
|
public void test() {
|
||||||
ListNode root = ListNodeUtils.build(new int[]{1, 1, 2,2,2});
|
ListNode root = ListNodeUtils.build(new int[]{1, 1, 2, 2, 2});
|
||||||
ListNodeUtils.print(deleteDuplicates(root));
|
ListNodeUtils.print(deleteDuplicates(root));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +39,7 @@ public class DeleteDuplicatesII {
|
||||||
temp1 = temp1.next;
|
temp1 = temp1.next;
|
||||||
}
|
}
|
||||||
temp.next = temp1.next;
|
temp.next = temp1.next;
|
||||||
}else {
|
} else {
|
||||||
temp = temp.next;
|
temp = temp.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,4 +49,31 @@ public class DeleteDuplicatesII {
|
||||||
return fake.next;
|
return fake.next;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ListNode deleteDuplicates1(ListNode head) {
|
||||||
|
|
||||||
|
if (head == null) {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
ListNode fake = new ListNode();
|
||||||
|
fake.next = head;
|
||||||
|
ListNode temp = fake;
|
||||||
|
|
||||||
|
while (temp.next != null) {
|
||||||
|
//存在重复
|
||||||
|
if (temp.next.next != null && temp.next.val == temp.next.next.val) {
|
||||||
|
ListNode temp1 = temp.next.next;
|
||||||
|
while (temp1.next != null && temp1.val == temp1.next.val) {
|
||||||
|
temp1 = temp1.next;
|
||||||
|
}
|
||||||
|
temp.next = temp1.next;
|
||||||
|
} else {
|
||||||
|
temp = temp.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fake.next;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
package com.markilue.leecode.listnode.selftry;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.listnode.selftry
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-04 13:45
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣146 LRU缓存:
|
||||||
|
* 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
|
||||||
|
* 实现 LRUCache 类:
|
||||||
|
* LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
|
||||||
|
* int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
|
||||||
|
* void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
|
||||||
|
* 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class LRUCache {
|
||||||
|
|
||||||
|
int size;
|
||||||
|
int capacity;
|
||||||
|
DNode head;
|
||||||
|
DNode tail;
|
||||||
|
Map<Integer, DNode> map;
|
||||||
|
|
||||||
|
|
||||||
|
//HashMap+链表:本质上就是LinkedHashMap
|
||||||
|
public LRUCache() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LRUCache(int capacity) {
|
||||||
|
this.capacity = capacity;
|
||||||
|
head = new DNode();
|
||||||
|
tail = new DNode();
|
||||||
|
map = new HashMap<>();
|
||||||
|
size = 0;
|
||||||
|
head.next = tail;
|
||||||
|
tail.prev = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get(int key) {
|
||||||
|
DNode dNode = map.get(key);
|
||||||
|
if (dNode == null) return -1;
|
||||||
|
deleteNode(dNode);
|
||||||
|
addToHead(dNode);
|
||||||
|
return dNode.value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(int key, int value) {
|
||||||
|
DNode dNode = map.get(key);
|
||||||
|
if(dNode==null){
|
||||||
|
DNode node = new DNode(key,value);
|
||||||
|
map.put(key, node);
|
||||||
|
addToHead(node);
|
||||||
|
size++;
|
||||||
|
if (size > capacity) {
|
||||||
|
DNode dNode1 = deleteTailNode();
|
||||||
|
map.remove(dNode1.key);
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
dNode.value=value;
|
||||||
|
deleteNode(dNode);
|
||||||
|
addToHead(dNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToHead(DNode node) {
|
||||||
|
head.next.prev = node;
|
||||||
|
node.next = head.next;
|
||||||
|
head.next = node;
|
||||||
|
node.prev = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
//自删除
|
||||||
|
public void deleteNode(DNode node) {
|
||||||
|
node.prev.next = node.next;
|
||||||
|
node.next.prev = node.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除尾节点
|
||||||
|
public DNode deleteTailNode() {
|
||||||
|
|
||||||
|
DNode prev = tail.prev;
|
||||||
|
deleteNode(prev);
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DNode {
|
||||||
|
|
||||||
|
DNode prev;
|
||||||
|
DNode next;
|
||||||
|
int value;
|
||||||
|
int key;
|
||||||
|
|
||||||
|
public DNode() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DNode(int key , int value) {
|
||||||
|
this.key=key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DNode(int value, DNode prev, DNode next) {
|
||||||
|
this.value = value;
|
||||||
|
this.prev = prev;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.markilue.leecode.listnode.selftry;
|
||||||
|
|
||||||
|
import com.markilue.leecode.listnode.ListNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.listnode.selftry
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-04 12:56
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣143 重排链表:
|
||||||
|
* 给定一个单链表 L 的头节点 head ,单链表 L 表示为:
|
||||||
|
* L0 → L1 → … → Ln - 1 → Ln
|
||||||
|
* 请将其重新排列后变为:
|
||||||
|
* L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
|
||||||
|
* 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class ReorderList {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归法
|
||||||
|
* @param head
|
||||||
|
*/
|
||||||
|
ListNode p;
|
||||||
|
|
||||||
|
public void reorderList(ListNode head) {
|
||||||
|
p = head;
|
||||||
|
recur(head);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recur(ListNode head) {
|
||||||
|
if (head == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recur(head.next);
|
||||||
|
if (p.next == null || p == head || head.next == p) {
|
||||||
|
//判断当前节点是否需要合并
|
||||||
|
p.next = null;//不需要合并了,直接把p置为null
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
head.next = p.next;//把p的后面拼在head的后面
|
||||||
|
p.next = head;//把head加在p的后面
|
||||||
|
p = p.next.next;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package com.markilue.leecode.listnode.selftry;
|
package com.markilue.leecode.listnode.selftry;
|
||||||
|
|
||||||
|
import com.markilue.leecode.listnode.ListNode;
|
||||||
import com.markilue.leecode.listnode.T04_swapPairs;
|
import com.markilue.leecode.listnode.T04_swapPairs;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class reverseKGroup {
|
public class reverseKGroup {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
@ -10,24 +13,53 @@ public class reverseKGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListNode reverseKGroup(ListNode head, int k) {
|
public ListNode reverseKGroup(ListNode head, int k) {
|
||||||
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static class ListNode {
|
|
||||||
int val;
|
|
||||||
T04_swapPairs.ListNode next;
|
|
||||||
|
|
||||||
ListNode() {
|
|
||||||
|
/**
|
||||||
|
* 反转部分链表
|
||||||
|
* @param head
|
||||||
|
* @param k
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ListNode reverseKGroup1(ListNode head, int k) {
|
||||||
|
if (head == null) {
|
||||||
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListNode(int val) {
|
ListNode temp = head;
|
||||||
this.val = val;
|
//寻找终点
|
||||||
|
for (int i = 0; i < k; i++) {
|
||||||
|
if (temp == null) return head;//没到k个,直接返回
|
||||||
|
temp = temp.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListNode(int val, T04_swapPairs.ListNode next) {
|
ListNode newHead = reverse(head, temp);
|
||||||
this.val = val;
|
head.next= reverseKGroup1(temp, k);
|
||||||
this.next = next;
|
return newHead;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListNode reverse(ListNode start, ListNode end) {
|
||||||
|
//反转部分链表
|
||||||
|
if (start == null) return start;
|
||||||
|
|
||||||
|
|
||||||
|
ListNode fake = new ListNode();
|
||||||
|
fake.next = start;
|
||||||
|
ListNode temp = start;
|
||||||
|
while (temp != end) {
|
||||||
|
ListNode tempnext = temp.next;
|
||||||
|
temp.next = fake.next;
|
||||||
|
fake.next = temp;
|
||||||
|
temp = tempnext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fake.next;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,45 @@
|
||||||
package com.markilue.leecode.listnode.selftry;
|
package com.markilue.leecode.listnode.selftry;
|
||||||
|
|
||||||
|
|
||||||
|
import com.markilue.leecode.listnode.ListNode;
|
||||||
|
import com.markilue.leecode.listnode.ListNodeUtils;
|
||||||
|
|
||||||
public class swapPairs {
|
public class swapPairs {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
ListNode l1 = new ListNode(1);
|
ListNode l1 = new ListNode(1);
|
||||||
//l1.next=new ListNode(2);
|
l1.next = new ListNode(2);
|
||||||
//l1.next.next=new ListNode(3);
|
l1.next.next = new ListNode(3);
|
||||||
//l1.next.next.next=new ListNode(4);
|
l1.next.next.next = new ListNode(4);
|
||||||
|
|
||||||
ListNode listNode = swapPairs(l1);
|
ListNode listNode = swapPairs1(l1);
|
||||||
|
ListNodeUtils.print(listNode);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ListNode swapPairs(ListNode head) {
|
public static ListNode swapPairs(ListNode head) {
|
||||||
if(head==null){
|
if (head == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ListNode dust=head;
|
ListNode dust = head;
|
||||||
ListNode swap=head.next;
|
ListNode swap = head.next;
|
||||||
int temp=0;
|
int temp = 0;
|
||||||
while (swap!=null){
|
while (swap != null) {
|
||||||
temp=swap.val;
|
temp = swap.val;
|
||||||
swap.val=head.val;
|
swap.val = head.val;
|
||||||
head.val=temp;
|
head.val = temp;
|
||||||
|
|
||||||
if(swap.next!=null){
|
if (swap.next != null) {
|
||||||
if(swap.next.next!=null){
|
if (swap.next.next != null) {
|
||||||
swap=swap.next.next;
|
swap = swap.next.next;
|
||||||
head=head.next.next;
|
head = head.next.next;
|
||||||
}else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,21 +47,30 @@ public class swapPairs {
|
||||||
return dust;
|
return dust;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ListNode {
|
|
||||||
int val;
|
|
||||||
ListNode next;
|
|
||||||
|
|
||||||
ListNode() {
|
public static ListNode swapPairs1(ListNode head) {
|
||||||
|
if (head == null || head.next == null) {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
ListNode fake = new ListNode();
|
||||||
|
fake.next = head;
|
||||||
|
ListNode tempcur = fake;
|
||||||
|
|
||||||
|
while (tempcur != null && tempcur.next != null) {
|
||||||
|
ListNode temp = tempcur.next.next;
|
||||||
|
if (tempcur.next.next != null) {
|
||||||
|
tempcur.next.next = tempcur.next.next.next;
|
||||||
|
temp.next = tempcur.next;
|
||||||
|
tempcur.next=temp;
|
||||||
|
}
|
||||||
|
tempcur = tempcur.next.next;
|
||||||
|
// tempcur = temp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListNode(int val) {
|
return fake.next;
|
||||||
this.val = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListNode(int val, ListNode next) {
|
|
||||||
this.val = val;
|
|
||||||
this.next = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,719 @@
|
||||||
|
use sqlpractice;
|
||||||
|
|
||||||
|
# 学生表Student
|
||||||
|
create table Student
|
||||||
|
(
|
||||||
|
SId varchar(10),
|
||||||
|
Sname varchar(10),
|
||||||
|
Sage datetime,
|
||||||
|
Ssex varchar(10)
|
||||||
|
);
|
||||||
|
insert into Student
|
||||||
|
values ('01', '赵雷', '1990-01-01', '男');
|
||||||
|
insert into Student
|
||||||
|
values ('02', '钱电', '1990-12-21', '男');
|
||||||
|
insert into Student
|
||||||
|
values ('03', '孙风', '1990-05-20', '男');
|
||||||
|
insert into Student
|
||||||
|
values ('04', '李云', '1990-08-06', '男');
|
||||||
|
insert into Student
|
||||||
|
values ('05', '周梅', '1991-12-01', '女');
|
||||||
|
insert into Student
|
||||||
|
values ('06', '吴兰', '1992-03-01', '女');
|
||||||
|
insert into Student
|
||||||
|
values ('07', '郑竹', '1989-07-01', '女');
|
||||||
|
insert into Student
|
||||||
|
values ('09', '张三', '2017-12-20', '女');
|
||||||
|
insert into Student
|
||||||
|
values ('10', '李四', '2017-12-25', '女');
|
||||||
|
insert into Student
|
||||||
|
values ('11', '李四', '2017-12-30', '女');
|
||||||
|
insert into Student
|
||||||
|
values ('12', '赵六', '2017-01-01', '女');
|
||||||
|
insert into Student
|
||||||
|
values ('13', '孙七', '2018-01-01', '女');
|
||||||
|
|
||||||
|
# 科目表
|
||||||
|
create table Course
|
||||||
|
(
|
||||||
|
CId varchar(10),
|
||||||
|
Cname nvarchar(10),
|
||||||
|
TId varchar(10)
|
||||||
|
);
|
||||||
|
insert into Course
|
||||||
|
values ('01', '语文', '02');
|
||||||
|
insert into Course
|
||||||
|
values ('02', '数学', '01');
|
||||||
|
insert into Course
|
||||||
|
values ('03', '英语', '03');
|
||||||
|
|
||||||
|
# 教师表
|
||||||
|
create table Teacher
|
||||||
|
(
|
||||||
|
TId varchar(10),
|
||||||
|
Tname varchar(10)
|
||||||
|
);
|
||||||
|
insert into Teacher
|
||||||
|
values ('01', '张三');
|
||||||
|
insert into Teacher
|
||||||
|
values ('02', '李四');
|
||||||
|
insert into Teacher
|
||||||
|
values ('03', '王五');
|
||||||
|
|
||||||
|
# 成绩表SC
|
||||||
|
create table SC
|
||||||
|
(
|
||||||
|
SId varchar(10),
|
||||||
|
CId varchar(10),
|
||||||
|
score decimal(18, 1)
|
||||||
|
);
|
||||||
|
insert into SC
|
||||||
|
values ('01', '01', 80);
|
||||||
|
insert into SC
|
||||||
|
values ('01', '02', 90);
|
||||||
|
insert into SC
|
||||||
|
values ('01', '03', 99);
|
||||||
|
insert into SC
|
||||||
|
values ('02', '01', 70);
|
||||||
|
insert into SC
|
||||||
|
values ('02', '02', 60);
|
||||||
|
insert into SC
|
||||||
|
values ('02', '03', 80);
|
||||||
|
insert into SC
|
||||||
|
values ('03', '01', 80);
|
||||||
|
insert into SC
|
||||||
|
values ('03', '02', 80);
|
||||||
|
insert into SC
|
||||||
|
values ('03', '03', 80);
|
||||||
|
insert into SC
|
||||||
|
values ('04', '01', 50);
|
||||||
|
insert into SC
|
||||||
|
values ('04', '02', 30);
|
||||||
|
insert into SC
|
||||||
|
values ('04', '03', 20);
|
||||||
|
insert into SC
|
||||||
|
values ('05', '01', 76);
|
||||||
|
insert into SC
|
||||||
|
values ('05', '02', 87);
|
||||||
|
insert into SC
|
||||||
|
values ('06', '01', 31);
|
||||||
|
insert into SC
|
||||||
|
values ('06', '03', 34);
|
||||||
|
insert into SC
|
||||||
|
values ('07', '02', 89);
|
||||||
|
insert into SC
|
||||||
|
values ('07', '03', 98);
|
||||||
|
|
||||||
|
|
||||||
|
#TODO 1、查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数
|
||||||
|
|
||||||
|
select Student.sid, sname, sage, Ssex, s1, s2
|
||||||
|
from student
|
||||||
|
join
|
||||||
|
(select t1.SId, s1, s2
|
||||||
|
from (select SId, score s1
|
||||||
|
from sc
|
||||||
|
where CId = '01') t1
|
||||||
|
join
|
||||||
|
(select SId, score s2
|
||||||
|
from sc
|
||||||
|
where CId = '02') t2 on t1.SId = t2.SId and t1.s1 > t2.s2) t3 on Student.SId = t3.SId;
|
||||||
|
|
||||||
|
#TODO 2.1、查询同时存在" 01 "课程和" 02 "课程的情况
|
||||||
|
select t1.SId, s1, s2
|
||||||
|
from (select SId, score s1
|
||||||
|
from sc
|
||||||
|
where CId = '01') t1
|
||||||
|
join
|
||||||
|
(select SId, score s2
|
||||||
|
from sc
|
||||||
|
where CId = '02') t2 on t1.SId = t2.SId;
|
||||||
|
|
||||||
|
#TODO 2.2、查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
|
||||||
|
select t1.sid, s1, s2
|
||||||
|
from (select SId, score s1
|
||||||
|
from sc
|
||||||
|
where CId = '01') t1
|
||||||
|
left join (select SId, score s2
|
||||||
|
from sc
|
||||||
|
where CId = '02') t2 on t1.SId = t2.SId;
|
||||||
|
|
||||||
|
|
||||||
|
#TODO 2.3、查询不存在" 01 "课程但存在" 02 "课程的情况
|
||||||
|
select t2.sid, s1, s2
|
||||||
|
from (select SId, score s1
|
||||||
|
from sc
|
||||||
|
where CId = '01') t1
|
||||||
|
right join (select SId, score s2
|
||||||
|
from sc
|
||||||
|
where CId = '02') t2 on t1.SId = t2.SId;
|
||||||
|
|
||||||
|
#TODO 3、查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
|
||||||
|
-- 查询平均成绩大于等于 60 分的同学
|
||||||
|
select SId, sum(score) / count(score) avg
|
||||||
|
from sc
|
||||||
|
group by sid
|
||||||
|
having avg > 60;
|
||||||
|
|
||||||
|
-- 查询这些学生的相关信息
|
||||||
|
select t1.sid, Sname, avg
|
||||||
|
from student
|
||||||
|
right join (select SId, sum(score) / count(score) avg
|
||||||
|
from sc
|
||||||
|
group by sid
|
||||||
|
having avg > 60) t1 on Student.SId = t1.SId;
|
||||||
|
|
||||||
|
#TODO 4、查询在 SC 表存在成绩的学生信息
|
||||||
|
-- 存在成绩+去重
|
||||||
|
select sid
|
||||||
|
from sc
|
||||||
|
where score is not null
|
||||||
|
group by sid;
|
||||||
|
-- 查询对应的信息
|
||||||
|
select t1.sid, Sname, Sage, Ssex
|
||||||
|
from student
|
||||||
|
right join (select sid
|
||||||
|
from sc
|
||||||
|
where score is not null
|
||||||
|
group by sid) t1 on Student.SId = t1.SId;
|
||||||
|
|
||||||
|
#TODO 5、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
|
||||||
|
-- 查询有成绩的
|
||||||
|
select sid, count(score) c1, sum(score) s1
|
||||||
|
from sc
|
||||||
|
group by sid;
|
||||||
|
|
||||||
|
select Student.sid, sname, c1, s1
|
||||||
|
from student
|
||||||
|
left join(select sid, count(score) c1, sum(score) s1
|
||||||
|
from sc
|
||||||
|
group by sid) t1 on Student.sid = t1.SId;
|
||||||
|
|
||||||
|
#TODO 6、查有成绩的学生信息
|
||||||
|
-- 有成绩的学生
|
||||||
|
select distinct(sid)
|
||||||
|
from sc
|
||||||
|
where score is not null;
|
||||||
|
-- 查询对应的信息
|
||||||
|
select Student.sid, Student.sname, Student.sage, ssex
|
||||||
|
from student
|
||||||
|
right join (select distinct(sid) sid
|
||||||
|
from sc
|
||||||
|
where score is not null) t1 on Student.SId = t1.SId;
|
||||||
|
|
||||||
|
#TODO 7、查询「李」姓老师的数量
|
||||||
|
select count(TId)
|
||||||
|
from Teacher
|
||||||
|
where Tname like '李%';
|
||||||
|
|
||||||
|
#TODO 8、查询学过「张三」老师授课的同学的信息
|
||||||
|
|
||||||
|
-- 张三老师教过的课
|
||||||
|
select cid, t.TId
|
||||||
|
from Course
|
||||||
|
join
|
||||||
|
(select tid, tname from teacher where tname = '张三') t on Course.TId = t.TId;
|
||||||
|
|
||||||
|
-- 张三老师教过的课的学生
|
||||||
|
select sid, t2.CId
|
||||||
|
from sc
|
||||||
|
join (select cid, t.TId
|
||||||
|
from Course
|
||||||
|
join
|
||||||
|
(select tid, tname from teacher where tname = '张三') t on Course.TId = t.TId) t2
|
||||||
|
on sc.CId = t2.CId;
|
||||||
|
|
||||||
|
-- 详细信息
|
||||||
|
select t3.sid, Sname, sage, Ssex
|
||||||
|
from student
|
||||||
|
join(select sid, t2.CId
|
||||||
|
from sc
|
||||||
|
join (select cid, t.TId
|
||||||
|
from Course
|
||||||
|
join
|
||||||
|
(select tid, tname from teacher where tname = '张三') t on Course.TId = t.TId) t2
|
||||||
|
on sc.CId = t2.CId) t3 on Student.SId = t3.SId;
|
||||||
|
|
||||||
|
#TODO 9、查询没有学全所有课程的同学的信息
|
||||||
|
|
||||||
|
-- 查询全部course的数目
|
||||||
|
select count(cid) num
|
||||||
|
from course;
|
||||||
|
|
||||||
|
-- 查询没有学全所有课程的同学
|
||||||
|
select sid, count(cid) c1, num
|
||||||
|
from sc,
|
||||||
|
(select count(cid) num
|
||||||
|
from course) t2
|
||||||
|
group by sid
|
||||||
|
having c1 < t2.num;
|
||||||
|
|
||||||
|
-- 查询对应学生的信息
|
||||||
|
select S.sid, sname, Sage, Ssex
|
||||||
|
from Student
|
||||||
|
right join (select sid, count(cid) c1, num
|
||||||
|
from sc,
|
||||||
|
(select count(cid) num
|
||||||
|
from course) t2
|
||||||
|
group by sid
|
||||||
|
having c1 < t2.num) S on Student.SId = S.SId;
|
||||||
|
|
||||||
|
#TODO 10、查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
|
||||||
|
|
||||||
|
-- 学号01同学所学
|
||||||
|
SELECT CId
|
||||||
|
from sc
|
||||||
|
where SId = '01';
|
||||||
|
|
||||||
|
-- 所学相同
|
||||||
|
select Student.sid, sname, Sage, Ssex
|
||||||
|
from Student
|
||||||
|
where SId in
|
||||||
|
(select distinct (sid)
|
||||||
|
from sc
|
||||||
|
join(SELECT CId
|
||||||
|
from sc
|
||||||
|
where SId = '01') t1 on sc.CId = t1.CId
|
||||||
|
where SC.SId != '01');
|
||||||
|
|
||||||
|
#TODO 11、查询和" 01 "号的同学学习的课程完全相同的其他同学的信息
|
||||||
|
|
||||||
|
-- 先join得到所有的相同的课
|
||||||
|
|
||||||
|
-- 计算所有课的数目和原本的数目是否相等
|
||||||
|
select sc.sid
|
||||||
|
from sc
|
||||||
|
join(select CId
|
||||||
|
from sc
|
||||||
|
where SId = '01') t1 on sc.CId = t1.CId
|
||||||
|
where sid != '01'
|
||||||
|
group by SId
|
||||||
|
having count(sc.cid) = (select count(CId)
|
||||||
|
from sc
|
||||||
|
where SId = '01');
|
||||||
|
|
||||||
|
select *
|
||||||
|
from student
|
||||||
|
where Student.SId in (select sc.sid
|
||||||
|
from sc
|
||||||
|
join(select CId
|
||||||
|
from sc
|
||||||
|
where SId = '01') t1 on sc.CId = t1.CId
|
||||||
|
where sid != '01'
|
||||||
|
group by SId
|
||||||
|
having count(sc.cid) = (select count(CId)
|
||||||
|
from sc
|
||||||
|
where SId = '01'));
|
||||||
|
|
||||||
|
#TODO 12、查询没学过"张三"老师讲授的任一门课程的学生姓名
|
||||||
|
|
||||||
|
-- 查询张三老师教过的课
|
||||||
|
select cid
|
||||||
|
from course
|
||||||
|
join(select TId
|
||||||
|
from teacher
|
||||||
|
where Tname = '张三') t1
|
||||||
|
on Course.TId = t1.TId;
|
||||||
|
-- 查询学过张三老师教过的课的学生
|
||||||
|
select SId
|
||||||
|
from sc
|
||||||
|
where CId in (select cid
|
||||||
|
from course
|
||||||
|
join(select TId
|
||||||
|
from teacher
|
||||||
|
where Tname = '张三') t1
|
||||||
|
on Course.TId = t1.TId);
|
||||||
|
-- 查询没有学过张三老师教过的课的学生
|
||||||
|
select *
|
||||||
|
from student
|
||||||
|
where SId not in (select SId
|
||||||
|
from sc
|
||||||
|
where CId in (select cid
|
||||||
|
from course
|
||||||
|
where tid in (select TId
|
||||||
|
from teacher
|
||||||
|
where Tname = '张三')));
|
||||||
|
|
||||||
|
# TODO 13、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
|
||||||
|
|
||||||
|
-- 查询两门及其以上不及格课程的同学的学号
|
||||||
|
select sid, count(CId) c1
|
||||||
|
from sc
|
||||||
|
where score < 60
|
||||||
|
group by sid
|
||||||
|
having c1 >= 2;
|
||||||
|
|
||||||
|
-- 查询这些人的平均成绩
|
||||||
|
select sid, avg(score) avg
|
||||||
|
from sc
|
||||||
|
where SId in
|
||||||
|
(select sid
|
||||||
|
from sc
|
||||||
|
where score < 60
|
||||||
|
group by sid
|
||||||
|
having count(CId) >= 2)
|
||||||
|
group by sid;
|
||||||
|
-- 查询全部
|
||||||
|
select t1.sid, Sname, avg
|
||||||
|
from student
|
||||||
|
join
|
||||||
|
(select sid, avg(score) avg
|
||||||
|
from sc
|
||||||
|
where SId in
|
||||||
|
(select sid
|
||||||
|
from sc
|
||||||
|
where score < 60
|
||||||
|
group by sid
|
||||||
|
having count(CId) >= 2)
|
||||||
|
group by sid) t1 on Student.SId = t1.SId;
|
||||||
|
|
||||||
|
#TODO 14、检索" 01 "课程分数小于 60,按分数降序排列的学生信息
|
||||||
|
-- 降序学生
|
||||||
|
select sid, score
|
||||||
|
from sc
|
||||||
|
where CId = '01'
|
||||||
|
and score < 60
|
||||||
|
order by score desc;
|
||||||
|
|
||||||
|
select *
|
||||||
|
from Student
|
||||||
|
join
|
||||||
|
(select sid, score
|
||||||
|
from sc
|
||||||
|
where CId = '01'
|
||||||
|
and score < 60
|
||||||
|
order by score desc) t1 on Student.SId = t1.SId;
|
||||||
|
|
||||||
|
#TODO 15、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
|
||||||
|
select sid, CId, score, avg
|
||||||
|
from (select sid,
|
||||||
|
CId,
|
||||||
|
score,
|
||||||
|
avg(score) over (partition by sid) avg
|
||||||
|
from sc) t1
|
||||||
|
order by avg desc;
|
||||||
|
|
||||||
|
|
||||||
|
#TODO 16、查询各科成绩最高分、最低分和平均分:
|
||||||
|
select cid, max(score), min(score), avg(score)
|
||||||
|
from sc
|
||||||
|
group by cid;
|
||||||
|
|
||||||
|
#TODO 17.1、按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
|
||||||
|
|
||||||
|
-- 窗口函数
|
||||||
|
select cid, sid, score, rank() over (partition by CId order by score desc)
|
||||||
|
from sc;
|
||||||
|
|
||||||
|
-- 师兄非窗口函数法
|
||||||
|
SELECT *, COUNT(*)
|
||||||
|
FROM sc a
|
||||||
|
LEFT JOIN
|
||||||
|
sc b
|
||||||
|
ON a.cid = b.cid AND a.score <= b.score
|
||||||
|
GROUP BY a.cid, a.sid, a.score
|
||||||
|
ORDER BY a.cid DESC, a.score DESC;
|
||||||
|
|
||||||
|
#TODO 17.2、按各科成绩进行排序,并显示排名, Score 重复时合并名次
|
||||||
|
-- 窗口函数
|
||||||
|
select cid, sid, score, dense_rank() over (partition by CId order by score desc)
|
||||||
|
from sc;
|
||||||
|
-- 师兄非窗口函数法 (应该有问题)
|
||||||
|
SELECT *, COUNT(*)
|
||||||
|
FROM sc a
|
||||||
|
LEFT JOIN
|
||||||
|
sc b
|
||||||
|
ON a.cid = b.cid AND a.score < b.score
|
||||||
|
GROUP BY a.cid, a.sid, a.score
|
||||||
|
ORDER BY a.cid DESC, a.score DESC;
|
||||||
|
|
||||||
|
|
||||||
|
# TODO 17.3、查询学生的总成绩,并进行排名,总分重复时保留名次空缺
|
||||||
|
|
||||||
|
-- 非窗口函数法
|
||||||
|
select t1.sid, t1.sum, count(*) rk
|
||||||
|
from (select sid, sum(score) sum
|
||||||
|
from sc
|
||||||
|
group by sid) t1
|
||||||
|
left join
|
||||||
|
(select sid, sum(score) sum
|
||||||
|
from sc
|
||||||
|
group by sid) t2 on t1.sum <= t2.sum
|
||||||
|
group by t1.sid, t1.sum
|
||||||
|
order by t1.sum desc;
|
||||||
|
|
||||||
|
-- 窗口函数法
|
||||||
|
select sid, sum, rank() over (order by sum desc) rk
|
||||||
|
from (select sid, sum(score) sum
|
||||||
|
from sc
|
||||||
|
group by sid) t1;
|
||||||
|
|
||||||
|
#TODO 17.4、 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
|
||||||
|
|
||||||
|
-- 窗口函数法
|
||||||
|
select sid, sum, dense_rank() over (order by sum desc) rk
|
||||||
|
from (select sid, sum(score) sum
|
||||||
|
from sc
|
||||||
|
group by sid) t1;
|
||||||
|
|
||||||
|
SET @crank = 0;
|
||||||
|
SELECT b.sid, b.a, @crank := @crank + 1 AS rank1
|
||||||
|
FROM (SELECT sid, SUM(score) AS a FROM sc GROUP BY sid ORDER BY a DESC) b;
|
||||||
|
|
||||||
|
#TODO 18.统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
|
||||||
|
|
||||||
|
select t1.cid,cname,you,liang,zhong,cha,you/total,liang/total,zhong/total,cha/total
|
||||||
|
from course
|
||||||
|
join
|
||||||
|
(
|
||||||
|
select cid,
|
||||||
|
sum(if(score >= 85 and score < 100, 1, 0)) you,
|
||||||
|
sum(if(score >= 70 and score < 85, 1, 0)) liang,
|
||||||
|
sum(if(score >= 60 and score < 70, 1, 0)) zhong,
|
||||||
|
sum(if(score > 0 and score < 60, 1, 0)) cha,
|
||||||
|
count(score) total
|
||||||
|
from sc
|
||||||
|
group by cid
|
||||||
|
)t1 on Course.CId=t1.CId;
|
||||||
|
|
||||||
|
-- 师兄写法
|
||||||
|
SELECT sc.cid,c.cname,
|
||||||
|
SUM(CASE WHEN score>85 AND score<=100 THEN 1 ELSE 0 END) AS '[100-85]',
|
||||||
|
SUM(CASE WHEN score>70 AND score<=85 THEN 1 ELSE 0 END) AS '[85-70]',
|
||||||
|
SUM(CASE WHEN score>60 AND score<=70 THEN 1 ELSE 0 END) AS '[70-60]',
|
||||||
|
SUM(CASE WHEN score<60 THEN 1 ELSE 0 END) AS '[60-0]',
|
||||||
|
SUM(CASE WHEN score>85 AND score<=100 THEN 1 ELSE 0 END)/COUNT(1) AS '[100-85]百分比',
|
||||||
|
SUM(CASE WHEN score>70 AND score<=85 THEN 1 ELSE 0 END)/COUNT(1) AS '[85-70]百分比',
|
||||||
|
SUM(CASE WHEN score>60 AND score<=70 THEN 1 ELSE 0 END)/COUNT(1) AS '[70-60]百分比',
|
||||||
|
SUM(CASE WHEN score<60 THEN 1 ELSE 0 END)/COUNT(1) AS '[60-0]百分比'
|
||||||
|
FROM sc ,course c
|
||||||
|
WHERE sc.cid=c.cid
|
||||||
|
GROUP BY sc.cid;
|
||||||
|
|
||||||
|
# TODO 19查询各科成绩前三名的记录
|
||||||
|
|
||||||
|
-- 窗口函数法
|
||||||
|
select cid,sid,score,rk
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select cid,sid,score,rank() over (partition by cid order by score desc) rk
|
||||||
|
from sc
|
||||||
|
) t1
|
||||||
|
where rk<=3;
|
||||||
|
|
||||||
|
-- 师兄非窗口函数写法
|
||||||
|
SELECT cid,sid,score FROM sc a
|
||||||
|
WHERE (SELECT COUNT(1) FROM sc b WHERE a.cid=b.cid AND a.score<=b.score)<=3
|
||||||
|
ORDER BY cid;
|
||||||
|
|
||||||
|
#TODO 20.查询每门课程被选修的学生数
|
||||||
|
select Course.cid,Cname,student_num
|
||||||
|
from course
|
||||||
|
left join
|
||||||
|
(
|
||||||
|
select cid,count(sid) student_num
|
||||||
|
from sc
|
||||||
|
group by cid
|
||||||
|
) t1 on Course.CId=t1.CId;
|
||||||
|
|
||||||
|
#TODO 21 查询出只选修两门课程的学生学号和姓名
|
||||||
|
select t1.sid,Sname
|
||||||
|
from student
|
||||||
|
join
|
||||||
|
(
|
||||||
|
select sid,count(cid) num
|
||||||
|
from sc
|
||||||
|
group by sid
|
||||||
|
having num=2
|
||||||
|
) t1 on Student.SId=t1.SId;
|
||||||
|
|
||||||
|
#TODO 22.查询男生、女生人数`student`
|
||||||
|
select sum(if(Ssex='男',1,0)) '男生数量',sum(if(Ssex='女',1,0)) '女生数量'
|
||||||
|
from student;
|
||||||
|
|
||||||
|
SELECT Ssex,COUNT(*) num FROM student GROUP BY ssex;
|
||||||
|
|
||||||
|
#TODO 23.查询名字中含有「风」字的学生信息
|
||||||
|
select *
|
||||||
|
from student
|
||||||
|
where Sname like '%风%';
|
||||||
|
|
||||||
|
#TODO 24.查询同名同姓学生名单,并统计同名人数
|
||||||
|
|
||||||
|
select sname ,count(sid) num
|
||||||
|
from student
|
||||||
|
group by sname
|
||||||
|
having num>1;
|
||||||
|
|
||||||
|
#TODO 25.查询 1990 年出生的学生名单
|
||||||
|
select sid,sname,Sage
|
||||||
|
from student
|
||||||
|
where year(Sage)='1990';
|
||||||
|
|
||||||
|
SELECT * FROM student WHERE sage LIKE '1990%';
|
||||||
|
|
||||||
|
#TODO 26.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
|
||||||
|
|
||||||
|
select cid,avg(score) avg
|
||||||
|
from sc
|
||||||
|
group by cid
|
||||||
|
order by avg desc,cid;
|
||||||
|
|
||||||
|
#TODO 27.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
|
||||||
|
|
||||||
|
select t1.sid,sname,avg
|
||||||
|
from student
|
||||||
|
right join
|
||||||
|
(
|
||||||
|
select sid,avg(score) avg
|
||||||
|
from sc
|
||||||
|
group by sid
|
||||||
|
having avg>=85
|
||||||
|
) t1 on Student.SId=t1.sid;
|
||||||
|
|
||||||
|
#TODO 28.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
|
||||||
|
|
||||||
|
select t1.sid,Sname,score
|
||||||
|
from student
|
||||||
|
join
|
||||||
|
(
|
||||||
|
select cid,SId,score
|
||||||
|
from sc
|
||||||
|
where cid=
|
||||||
|
(
|
||||||
|
select cid
|
||||||
|
from Course
|
||||||
|
where Cname ='数学'
|
||||||
|
)and score<60
|
||||||
|
) t1 on Student.SId=t1.SId;
|
||||||
|
|
||||||
|
#TODO 29.查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
|
||||||
|
|
||||||
|
select Student.sid,sname,ifnull(Cname,'无'),ifnull(score,0)
|
||||||
|
from student
|
||||||
|
left join
|
||||||
|
(
|
||||||
|
select sid,sc.cid,cname,score
|
||||||
|
from sc,course
|
||||||
|
where sc.cid=Course.CId
|
||||||
|
)t1 on Student.SId=t1.SId;
|
||||||
|
|
||||||
|
#TODO 30.查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
|
||||||
|
|
||||||
|
select sc.sid,sname,sc.cid,cname,score
|
||||||
|
from sc,course,student
|
||||||
|
where sc.CId=Course.CId and Student.SId=sc.SId and score>70;
|
||||||
|
|
||||||
|
SELECT t3.sname,t2.cname,t1.score FROM
|
||||||
|
(
|
||||||
|
(SELECT * FROM sc) t1
|
||||||
|
JOIN
|
||||||
|
(SELECT cid,cname FROM course) t2
|
||||||
|
JOIN
|
||||||
|
(SELECT sid,sname FROM student) t3
|
||||||
|
ON t1.cid=t2.cid AND t1.sid=t3.sid
|
||||||
|
)
|
||||||
|
WHERE t1.score > 70;
|
||||||
|
|
||||||
|
#TODO 31.查询不及格的课程
|
||||||
|
select sid,cid,score,(case when score<60 then 'fail' else 'success' end) result
|
||||||
|
from sc
|
||||||
|
where score<60;
|
||||||
|
|
||||||
|
# TODO 32.查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
|
||||||
|
select sid,Sname
|
||||||
|
from Student
|
||||||
|
where sid in
|
||||||
|
(select sid
|
||||||
|
from sc
|
||||||
|
where cid='01'and score>=80);
|
||||||
|
|
||||||
|
-- 也可以join获得具体的数
|
||||||
|
SELECT student.`SId`,student.`Sname`,sc.`CId`,sc.`score`
|
||||||
|
FROM sc,student
|
||||||
|
WHERE sc.`SId`=student.`SId` AND sc.`CId`=01 AND sc.`score`>=80;
|
||||||
|
|
||||||
|
#TODO 33.求每门课程的学生人数
|
||||||
|
select cid,count(sid) num
|
||||||
|
from sc
|
||||||
|
group by cid;
|
||||||
|
|
||||||
|
#TODO 34.成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
|
||||||
|
select student.sid, sname, sage, ssex,cid, score
|
||||||
|
from student
|
||||||
|
join
|
||||||
|
(
|
||||||
|
select sid,cid,score
|
||||||
|
from sc
|
||||||
|
where CId
|
||||||
|
in (select CId
|
||||||
|
from course
|
||||||
|
where TId in(select TId from teacher where Tname='张三'))
|
||||||
|
having score=max(score)
|
||||||
|
) t1 on Student.SId=t1.SId;
|
||||||
|
|
||||||
|
SELECT t2.sid,t2.cid,MAX(t2.score) FROM
|
||||||
|
(
|
||||||
|
(SELECT CId FROM course WHERE TId = (SELECT tid FROM teacher WHERE Tname='张三'))t1
|
||||||
|
JOIN
|
||||||
|
(SELECT * FROM sc) t2
|
||||||
|
ON t1.cid=t2.cid
|
||||||
|
);
|
||||||
|
|
||||||
|
#TODO 35.成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
|
||||||
|
|
||||||
|
-- 本人的应该有没有重复都行
|
||||||
|
select student.sid, sname, sage, ssex,cid, score
|
||||||
|
from student
|
||||||
|
join
|
||||||
|
(
|
||||||
|
select sid,cid,score
|
||||||
|
from sc
|
||||||
|
where CId
|
||||||
|
in (select CId
|
||||||
|
from course
|
||||||
|
where TId in(select TId from teacher where Tname='张三'))
|
||||||
|
having score=max(score)
|
||||||
|
) t1 on Student.SId=t1.SId;
|
||||||
|
|
||||||
|
# TODO 36.查询不同课程成绩相同的学生的学生编号、课程编号、学生编号
|
||||||
|
-- 窗口函数
|
||||||
|
-- 查询不同课程成绩相同的学生的学生编号
|
||||||
|
select sid,score,CId,num
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select sid,score,cid,count(cid) over(partition by sid,score) num
|
||||||
|
from sc
|
||||||
|
)t1
|
||||||
|
where num>1;
|
||||||
|
|
||||||
|
-- 师兄不用窗口函数法(有四门课及以上的应该不对)
|
||||||
|
SELECT * FROM sc a
|
||||||
|
WHERE sid IN
|
||||||
|
(SELECT sid FROM sc
|
||||||
|
GROUP BY sid
|
||||||
|
HAVING (COUNT(*)=2 AND COUNT(DISTINCT score)=1) -- 有两门课有重复的情况
|
||||||
|
OR (COUNT(*)=3 AND COUNT(DISTINCT score)<3)); -- 有三门课有重复的情况
|
||||||
|
|
||||||
|
-- 根据师兄的改进(去重前后不相等则有重复)
|
||||||
|
SELECT * FROM sc a
|
||||||
|
WHERE sid IN
|
||||||
|
(SELECT sid FROM sc
|
||||||
|
GROUP BY sid
|
||||||
|
HAVING COUNT(*) != COUNT(DISTINCT score));
|
||||||
|
|
||||||
|
#TODO 37.查询各学生的年龄,只按年份来算
|
||||||
|
|
||||||
|
SELECT sid,sname, YEAR(now())-YEAR(sage) age FROM student;
|
||||||
|
|
||||||
|
#TODO 38.按照出生日期来算,当前月日
|
||||||
|
SELECT sid,sname,TIMESTAMPDIFF(YEAR,sage,CURDATE()) age FROM student;
|
||||||
|
|
||||||
|
-- 自己的本办法
|
||||||
|
-- 判断年龄是否要-1
|
||||||
|
select sid,sname ,year(now())-year(Sage)-if(month(now())-month(Sage)>0||(month(now())=month(Sage)&&day(now())>=day(Sage)),0,1) age
|
||||||
|
from student;
|
||||||
|
|
||||||
|
#TODO 39.查询本周过生日的学生
|
||||||
|
SELECT * FROM student WHERE WEEKOFYEAR(sage)=WEEKOFYEAR(CURDATE())
|
||||||
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.markilue.leecode.test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.test
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-04-04 11:01
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣15题 三数之和:
|
||||||
|
* 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
|
||||||
|
* 你返回所有和为 0 且不重复的三元组。
|
||||||
|
* 注意:答案中不可以包含重复的三元组。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class ThreeSum {
|
||||||
|
|
||||||
|
|
||||||
|
public List<List<Integer>> threeSum(int[] nums) {
|
||||||
|
List<List<Integer>> result = new ArrayList<>();
|
||||||
|
if (nums.length < 3) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Arrays.sort(nums);
|
||||||
|
|
||||||
|
for (int i = 0; i < nums.length-2; i++) {
|
||||||
|
if (i != 0 && nums[i] == nums[i - 1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (nums[i] > 0) break;
|
||||||
|
|
||||||
|
int left = i + 1;
|
||||||
|
int right = nums.length - 1;
|
||||||
|
|
||||||
|
while (left < right) {
|
||||||
|
int sum = nums[i] + nums[left] + nums[right];
|
||||||
|
|
||||||
|
if (sum < 0) {
|
||||||
|
left++;
|
||||||
|
} else if (sum > 0) {
|
||||||
|
right--;
|
||||||
|
} else {
|
||||||
|
result.add(new ArrayList<>(Arrays.asList(nums[i], nums[left], nums[right])));
|
||||||
|
|
||||||
|
while (left < right && nums[left] == nums[left + 1]) left++;
|
||||||
|
while (left < right && nums[right] == nums[right - 1]) right--;
|
||||||
|
left++;
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.markilue.leecode.test;
|
package com.markilue.leecode.test;
|
||||||
|
|
||||||
|
import com.markilue.leecode.hot100.T55_LFUCache;
|
||||||
import com.markilue.leecode.tree.TreeNode;
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
@ -15,6 +16,32 @@ import java.util.ArrayList;
|
||||||
*/
|
*/
|
||||||
public class test {
|
public class test {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2(){
|
||||||
|
T55_LFUCache lfuCache = new T55_LFUCache(2);
|
||||||
|
lfuCache.put(1,1);
|
||||||
|
lfuCache.put(2,2);
|
||||||
|
System.out.println(lfuCache.get(1));
|
||||||
|
lfuCache.put(3,3);
|
||||||
|
System.out.println(lfuCache.get(2));
|
||||||
|
System.out.println(lfuCache.get(3));
|
||||||
|
lfuCache.put(4,4);
|
||||||
|
System.out.println(lfuCache.get(1));
|
||||||
|
System.out.println(lfuCache.get(3));
|
||||||
|
System.out.println(lfuCache.get(4));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("hello sta");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("hello world");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//测试ArrayList的index是否发生变化
|
//测试ArrayList的index是否发生变化
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.markilue.leecode.test;
|
package com.markilue.leecode.test;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
|
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -14,53 +15,53 @@ import java.util.Scanner;
|
||||||
public class testAnt {
|
public class testAnt {
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
// public static void main(String[] args) {
|
||||||
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
String input = sc.nextLine();
|
|
||||||
|
|
||||||
new testAnt().test(input);
|
|
||||||
// StringBuilder output = new StringBuilder();
|
|
||||||
// int left = 0;
|
|
||||||
//
|
//
|
||||||
// //去除前面的
|
// Scanner sc = new Scanner(System.in);
|
||||||
// while (left < input.length() && input.charAt(left) == ' ') {
|
// String input = sc.nextLine();
|
||||||
// left++;
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// boolean isCapital = true; // 首字母是否大写
|
// new testAnt().test(input);
|
||||||
// for (int i = left; i < input.length(); i++) {
|
//// StringBuilder output = new StringBuilder();
|
||||||
// char c = input.charAt(i);
|
//// int left = 0;
|
||||||
// if (c == ' ') {
|
////
|
||||||
// if (i > 0 && input.charAt(i - 1) == '.') {
|
//// //去除前面的
|
||||||
// output.deleteCharAt(output.length() - 1);
|
//// while (left < input.length() && input.charAt(left) == ' ') {
|
||||||
// }
|
//// left++;
|
||||||
// // 跳过多余的空格
|
//// }
|
||||||
// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') {
|
////
|
||||||
// i++;
|
//// boolean isCapital = true; // 首字母是否大写
|
||||||
// }
|
//// for (int i = left; i < input.length(); i++) {
|
||||||
// if (input.charAt(i + 1) != '.') {
|
//// char c = input.charAt(i);
|
||||||
// output.append(' ');
|
//// if (c == ' ') {
|
||||||
// }
|
//// if (i > 0 && input.charAt(i - 1) == '.') {
|
||||||
// } else if (c == '.') {
|
//// output.deleteCharAt(output.length() - 1);
|
||||||
// // 句号后面要加一个空格
|
//// }
|
||||||
// output.append(". ");
|
//// // 跳过多余的空格
|
||||||
// isCapital = true; // 下一句话的首字母要大写
|
//// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') {
|
||||||
// } else {
|
//// i++;
|
||||||
// if (isCapital) {
|
//// }
|
||||||
// // 首字母要大写
|
//// if (input.charAt(i + 1) != '.') {
|
||||||
// output.append(Character.toUpperCase(c));
|
//// output.append(' ');
|
||||||
// isCapital = false;
|
//// }
|
||||||
// } else {
|
//// } else if (c == '.') {
|
||||||
// output.append(c);
|
//// // 句号后面要加一个空格
|
||||||
// }
|
//// output.append(". ");
|
||||||
// }
|
//// isCapital = true; // 下一句话的首字母要大写
|
||||||
// }
|
//// } else {
|
||||||
|
//// if (isCapital) {
|
||||||
|
//// // 首字母要大写
|
||||||
|
//// output.append(Character.toUpperCase(c));
|
||||||
|
//// isCapital = false;
|
||||||
|
//// } else {
|
||||||
|
//// output.append(c);
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// System.out.println(output.toString());
|
||||||
|
// sc.close();
|
||||||
//
|
//
|
||||||
// System.out.println(output.toString());
|
// }
|
||||||
sc.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void test(String str) {
|
public void test(String str) {
|
||||||
|
|
@ -106,4 +107,68 @@ public class testAnt {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// public static void main(String[] args) {
|
||||||
|
// Scanner scanner = new Scanner(System.in);
|
||||||
|
// int k = scanner.nextInt();
|
||||||
|
// int count = 0;
|
||||||
|
// for (int i = 0; i < 65536; i++) {
|
||||||
|
// String hex = String.format("%04x", i); // 将整数转换成长度为 4 的十六进制数
|
||||||
|
// if (isGoodHex(hex)) {
|
||||||
|
// count++;
|
||||||
|
// if (count == k) {
|
||||||
|
// System.out.println(hex);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static boolean isGoodHex(String hex) {
|
||||||
|
// Set<Character> digits = new HashSet<>();
|
||||||
|
// for (char c : hex.toCharArray()) {
|
||||||
|
// digits.add(c);
|
||||||
|
// }
|
||||||
|
// return digits.size() == 4;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String s = "????(?"; // 待匹配的字符串
|
||||||
|
int left = 0, right = 0, count = 0; // 分别记录左括号、右括号和合法的括号对的数量
|
||||||
|
Stack<Integer> stack = new Stack<>(); // 栈,用于记录左括号和 '?' 的下标
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
char c = s.charAt(i);
|
||||||
|
if (c == '(' || c == '?') {
|
||||||
|
stack.push(i);
|
||||||
|
if (c == '(') {
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stack.pop();
|
||||||
|
if (c == ')') {
|
||||||
|
right++;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!stack.isEmpty()) { // 处理剩余的左括号或 '?'
|
||||||
|
int index = stack.pop();
|
||||||
|
if (s.charAt(index) == '(') {
|
||||||
|
left--;
|
||||||
|
} else {
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count += Math.min(left, right); // '?' 可以代替左括号或右括号,因此左右括号数量较小的值为合法的括号对数量
|
||||||
|
System.out.println(count);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue