修改LeetCode目录结构,不分类
This commit is contained in:
parent
25f4784daa
commit
aee514923d
@ -14,7 +14,6 @@
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
@ -24,6 +23,12 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--jdbc Driver-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
@ -33,7 +38,6 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- JPA API -->
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
|
165
ForJdk17/src/main/java/cn/whaifree/LCR/LCR031.java
Normal file
165
ForJdk17/src/main/java/cn/whaifree/LCR/LCR031.java
Normal file
@ -0,0 +1,165 @@
|
||||
package cn.whaifree.LCR;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/24 15:09
|
||||
* @注释
|
||||
*/
|
||||
public class LCR031 {
|
||||
|
||||
|
||||
class LRUCache {
|
||||
int maxCap = 0;
|
||||
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>();
|
||||
|
||||
public LRUCache(int capacity) {
|
||||
maxCap = capacity;
|
||||
}
|
||||
|
||||
public int get(int key) {
|
||||
if (map.containsKey(key)) {
|
||||
Integer i = map.get(key);
|
||||
map.remove(key);
|
||||
map.put(key, i);
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void put(int key, int value) {
|
||||
if (map.containsKey(key)) {
|
||||
map.remove(key);
|
||||
map.get(key);
|
||||
map.put(key, value);
|
||||
return;
|
||||
}
|
||||
|
||||
map.put(key, value);
|
||||
if (map.size() > maxCap) {
|
||||
for (Integer i : map.keySet()) {
|
||||
map.remove(i); // 只删除一个
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
// ["LRUCache","put","put","get","put","put","get"]
|
||||
// [[2],[2,1],[2,2],[2],[1,1],[4,1],[2]]
|
||||
LRUCache cache = new LRUCache(2);
|
||||
cache.put(2, 1);
|
||||
cache.put(2, 2);
|
||||
System.out.println(cache.get(2));
|
||||
cache.put(1, 1);
|
||||
cache.put(4, 1);
|
||||
System.out.println(cache.get(2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Your LRUCache object will be instantiated and called as such:
|
||||
* LRUCache obj = new LRUCache(capacity);
|
||||
* int param_1 = obj.get(key);
|
||||
* obj.put(key,value);
|
||||
*/
|
||||
@Test
|
||||
public void test2() {
|
||||
P2.LRUCache cache = new P2.LRUCache(2);
|
||||
cache.put(2, 1);
|
||||
cache.put(2, 2);
|
||||
System.out.println(cache.get(2));
|
||||
cache.put(1, 1);
|
||||
cache.put(4, 1);
|
||||
System.out.println(cache.get(2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class P2{
|
||||
|
||||
|
||||
static class Entry{
|
||||
Entry before;
|
||||
Entry next;
|
||||
int value;
|
||||
int key;
|
||||
|
||||
public Entry(Entry before, Entry next, int value, int key) {
|
||||
this.before = before;
|
||||
this.next = next;
|
||||
this.value = value;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
static class LRUCache {
|
||||
Map<Integer, Entry> map = new HashMap<>();
|
||||
Entry head;
|
||||
Entry tail;
|
||||
int maxSize;
|
||||
|
||||
public LRUCache(int capacity) {
|
||||
maxSize = capacity;
|
||||
head = new Entry(null, null, Integer.MIN_VALUE, Integer.MIN_VALUE);
|
||||
tail = new Entry(null, null, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
tail.before = head;
|
||||
head.next = tail;
|
||||
}
|
||||
|
||||
public void addToHead(Entry entry) {
|
||||
Entry next = head.next;
|
||||
head.next = entry;
|
||||
entry.before = head;
|
||||
entry.next = next;
|
||||
next.before = entry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void removeIndex(Entry entry) {
|
||||
entry.before.next = entry.next;
|
||||
entry.next.before = entry.before;
|
||||
}
|
||||
|
||||
|
||||
public int get(int key) {
|
||||
if (map.containsKey(key)) {
|
||||
Entry entry = map.get(key);
|
||||
removeIndex(entry);
|
||||
addToHead(entry);
|
||||
return entry.value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void put(int key, int value) {
|
||||
if (map.containsKey(key)) {
|
||||
Entry entry = map.get(key);
|
||||
entry.value = value;
|
||||
removeIndex(entry);
|
||||
addToHead(entry);
|
||||
return;
|
||||
}
|
||||
Entry newEntry = new Entry(null, null, value, key);
|
||||
addToHead(newEntry);
|
||||
map.put(key, newEntry);
|
||||
if (map.size() > maxSize) {
|
||||
Entry before = tail.before;
|
||||
map.remove(before.key);
|
||||
removeIndex(tail.before);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
198
ForJdk17/src/main/java/cn/whaifree/LCR/LCR106.java
Normal file
198
ForJdk17/src/main/java/cn/whaifree/LCR/LCR106.java
Normal file
@ -0,0 +1,198 @@
|
||||
package cn.whaifree.LCR;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/25 15:03
|
||||
* @注释
|
||||
*/
|
||||
public class LCR106 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// [[1,2,3],[0,2],[0,1,3],[0,2]]
|
||||
int[][] graph = {{1, 2, 3}, {0, 2}, {0, 1, 3}, {0, 2}};
|
||||
// [[],[2,4,6],[1,4,8,9],[7,8],[1,2,8,9],[6,9],[1,5,7,8,9],[3,6,9],[2,3,4,6,9],[2,4,5,6,7,8]]
|
||||
graph = new int[][]{{}, {2, 4, 6}, {1, 4, 8, 9}, {7, 8}, {1, 2, 8, 9}, {6, 9}, {1, 5, 7, 8, 9}, {3, 6, 9}, {2, 3, 4, 6, 9}, {2, 4, 5, 6, 7, 8}};
|
||||
Solution solution = new Solution();
|
||||
boolean bipartite = solution.isBipartite(graph);
|
||||
System.out.println(bipartite);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
private final static int UN_SIGN = 0;
|
||||
private final static int RED_SIGN = 1;
|
||||
private final static int BLACK_SIGN = 2;
|
||||
int[] color = null;
|
||||
boolean res = true;
|
||||
/**
|
||||
* 深度优先遍历dfs
|
||||
* 如果是没有标记过的,红标记为黑,黑标记为红
|
||||
* 如果是标记过的,如果颜色一样,直接返回false
|
||||
*
|
||||
* @param graph
|
||||
* @return
|
||||
*/
|
||||
public boolean isBipartite(int[][] graph) {
|
||||
int n = graph.length;
|
||||
color = new int[n];
|
||||
|
||||
|
||||
// 这个for确保每个连通的图,都遍历一遍
|
||||
// [[],[2,4,6],[1,4,8,9],[7,8],[1,2,8,9],[6,9],[1,5,7,8,9],[3,6,9],[2,3,4,6,9],[2,4,5,6,7,8]]
|
||||
// 比如这个,第一个0与任何都不连通,就会直接返回true,
|
||||
for (int i = 0; i < n && res; i++) {
|
||||
if (color[i] == UN_SIGN) {
|
||||
color[i] = RED_SIGN;
|
||||
dfs(graph, i, RED_SIGN);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param graph
|
||||
* @param now 现在是拿个节点I
|
||||
* @param nowColor 此节点now的颜色
|
||||
*/
|
||||
public void dfs(int[][] graph, int now, int nowColor) {
|
||||
int hopeNextColor;
|
||||
if (nowColor == RED_SIGN) {
|
||||
hopeNextColor = BLACK_SIGN;
|
||||
}else {
|
||||
hopeNextColor = RED_SIGN;
|
||||
}
|
||||
int[] targets = graph[now];
|
||||
for (int target : targets) {
|
||||
if (color[target] == UN_SIGN) {
|
||||
color[target] = hopeNextColor;
|
||||
dfs(graph, target, hopeNextColor);
|
||||
if (!res) { // 一旦有false直接返回,剪枝
|
||||
return;
|
||||
}
|
||||
} else if (color[target] != hopeNextColor) {
|
||||
// 本节点已经遍历过了,并且与期望不一样,直接false
|
||||
res = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
|
||||
private final static int UN_SIGN = 0;
|
||||
private final static int RED_SIGN = 1;
|
||||
private final static int BLACK_SIGN = 2;
|
||||
int[] color = null;
|
||||
boolean res = true;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param graph
|
||||
* @return
|
||||
*/
|
||||
public boolean isBipartite(int[][] graph) {
|
||||
int n = graph.length;
|
||||
color = new int[n];
|
||||
Arrays.fill(color, UN_SIGN);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (color[i] == UN_SIGN) {
|
||||
if (!WFS(graph, i, RED_SIGN)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean WFS(int[][] graph, int now, int nowColor) {
|
||||
Deque<Integer> queue = new LinkedList<>();
|
||||
queue.add(now);
|
||||
color[now] = RED_SIGN;
|
||||
while (!queue.isEmpty()) {
|
||||
Integer pop = queue.pop();
|
||||
int HopeNext = 0;
|
||||
if (color[pop] == RED_SIGN) {
|
||||
HopeNext = BLACK_SIGN;
|
||||
} else {
|
||||
HopeNext = RED_SIGN;
|
||||
}
|
||||
int[] Targets = graph[pop];
|
||||
for (int target : Targets) {
|
||||
if (color[target] == UN_SIGN) {
|
||||
color[target] = HopeNext;
|
||||
queue.add(target);
|
||||
}else if (color[target] != HopeNext) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// class Solution {
|
||||
// Set<Integer> set1;
|
||||
// Set<Integer> set2;
|
||||
// LinkedList<Integer> path;
|
||||
// /**
|
||||
// * 建立两个Set
|
||||
// *
|
||||
// * 递归深度遍历
|
||||
// * - 如果Set中存在,直接、return
|
||||
// * - 如果不存在加入Set
|
||||
// *
|
||||
// * @param graph
|
||||
// * @return
|
||||
// */
|
||||
// public boolean isBipartite(int[][] graph) {
|
||||
// set1 = new HashSet<>();
|
||||
// set2 = new HashSet<>();
|
||||
// path = new LinkedList<>();
|
||||
// path.add(0);
|
||||
// boolean dfs = dfs(graph, 0, true);
|
||||
// return dfs;
|
||||
// }
|
||||
//
|
||||
// public boolean dfs(int[][] graph,int now,boolean toSet1) {
|
||||
// if (set1.contains(now) || set2.contains(now)) {
|
||||
// return false;
|
||||
// }
|
||||
// if (toSet1) {
|
||||
// set1.add(now);
|
||||
// }else {
|
||||
// set2.add(now);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// int[] tos = graph[now];
|
||||
// for (int i = 0; i < tos.length; i++) {
|
||||
// int wantTo = tos[i];
|
||||
// // 这个边的两头在同一个集合
|
||||
// if (toSet1 && set1.contains(wantTo)) {
|
||||
// continue;
|
||||
// }
|
||||
// if (!toSet1 && set2.contains(wantTo)) {
|
||||
// continue;
|
||||
// }
|
||||
// path.add(wantTo);
|
||||
// if (dfs(graph, wantTo, !toSet1)) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// path.remove(path.size() - 1);
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/15 16:37
|
||||
* @注释
|
||||
*/
|
||||
public class LCR119 {
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {100, 4, 200, 1, 3, 2};
|
||||
System.out.println(new Solution().longestConsecutive(nums));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int longestConsecutive(int[] nums) {
|
||||
HashSet<Integer> set = new HashSet<>();
|
||||
for (int num : nums) {
|
||||
set.add(num);
|
||||
}
|
||||
|
||||
int max = 0;
|
||||
for (int num : nums) {
|
||||
if (set.contains(num- 1)) { // 1 2 3 4 只要保证set里没有0
|
||||
continue;
|
||||
}
|
||||
// int base = num;
|
||||
// int tmp = 0;
|
||||
// while (set.contains(base++)) {
|
||||
// tmp++;
|
||||
// }
|
||||
// max = Math.max(max, tmp);
|
||||
|
||||
int maxnum = num;
|
||||
while (set.contains(maxnum + 1)) {
|
||||
maxnum++;
|
||||
}
|
||||
max = Math.max(max, maxnum - num + 1);
|
||||
}
|
||||
return max;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/19 23:02
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode167 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
Solution1 solution = new Solution1();
|
||||
int[] ints = solution.twoSum(new int[]{2,7,11,15}, 9);
|
||||
System.out.println(ints[0] + " " + ints[1]);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int[] twoSum(int[] numbers, int target) {
|
||||
|
||||
for (int i = 0; i < numbers.length; i++) {
|
||||
int tar = target - numbers[i];
|
||||
int j = binarySearch(numbers, tar);
|
||||
if (j != -1 && i != j) {
|
||||
return i < j ? new int[]{i + 1, j + 1} : new int[]{j + 1, i + 1};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int binarySearch(int[] nums, int target) {
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
while (left <= right) {
|
||||
int mid = (left + right) / 2;
|
||||
if (nums[mid] == target) {
|
||||
return mid;
|
||||
} else if (nums[mid] < target) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public int[] twoSum(int[] numbers, int target) {
|
||||
int left = 0;
|
||||
int right = numbers.length - 1;
|
||||
while (left < right) {
|
||||
int sum = numbers[left] + numbers[right];
|
||||
if (sum == target) {
|
||||
return new int[]{left + 1, right + 1};
|
||||
} else if (sum < target) {
|
||||
left++;
|
||||
}else {
|
||||
right--;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/1 2:21
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode169
|
||||
{
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
|
||||
int[] nums = {2,2,1,1,1,2,2};
|
||||
Solution solution = new Solution();
|
||||
int i = solution.majorityElement(nums);
|
||||
System.out.println(i);
|
||||
}
|
||||
class Solution {
|
||||
/**
|
||||
* 遍历每个元素
|
||||
* count 为现在出现最多的数
|
||||
* - 如果count = 0 (表示发生了是和不是的变化)
|
||||
* - 这个元素出现的次数>=之前元素出现的个数
|
||||
* 所以基准变为这个元素
|
||||
* count = item == base : 1:-1
|
||||
*
|
||||
* 如果是这个元素+1,不是这个元素-1
|
||||
*
|
||||
* cge5 cge5 cge7
|
||||
* 1 2 1 2 1 0 1 0 1 2 1 0 1 2 3 4
|
||||
* [7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
|
||||
* 在遍历到数组中的第一个元素以及每个在 | 之后的元素时,candidate 都会因为 count 的值变为 0 而发生改变。最后一次 candidate 的值从 5 变为 7,也就是这个数组中的众数。
|
||||
*
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int majorityElement(int[] nums) {
|
||||
int count = 0;
|
||||
Integer candidate = null;
|
||||
|
||||
for (int num : nums) {
|
||||
if (count == 0) {
|
||||
candidate = num;
|
||||
System.out.println("基准元素:" + candidate);
|
||||
}
|
||||
count += (num == candidate) ? 1 : -1;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/16 12:15
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode189 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums = new int[]{-1};
|
||||
new Solution1().rotate(nums, 3);
|
||||
System.out.println(Arrays.toString(nums));
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Solution {
|
||||
public void rotate(int[] nums, int k) {
|
||||
int[] newNums = new int[nums.length];
|
||||
for (int i = 0; i < newNums.length; i++) {
|
||||
newNums[(i + k) % nums.length] = nums[i];
|
||||
}
|
||||
System.arraycopy(newNums, 0, nums, 0, nums.length);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public void rotate(int[] nums, int k) {
|
||||
k %= nums.length;
|
||||
reverse(nums, 0, nums.length - 1);
|
||||
reverse(nums, 0, k - 1);
|
||||
reverse(nums, k, nums.length - 1);
|
||||
}
|
||||
|
||||
public void reverse(int[] nums, int start, int end) {
|
||||
while (start < end) {
|
||||
swap(nums, start, end);
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
public void swap(int[] nums, int i, int j) {
|
||||
int temp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 209. 长度最小的子数组
|
||||
* 给定一个含有 n 个正整数的数组和一个正整数 target 。
|
||||
*
|
||||
* 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
|
||||
*
|
||||
* 示例 1:
|
||||
*
|
||||
* 输入:target = 7, nums = [2,3,1,2,4,3]
|
||||
* 输出:2
|
||||
* 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:target = 4, nums = [1,4,4]
|
||||
* 输出:1
|
||||
* 示例 3:
|
||||
*
|
||||
* 输入:target = 11, nums = [1,1,1,1,1,1,1,1]
|
||||
* 输出:0
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 1 <= target <= 109
|
||||
* 1 <= nums.length <= 105
|
||||
* 1 <= nums[i] <= 105
|
||||
*
|
||||
* 进阶:
|
||||
*
|
||||
* 如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
|
||||
*/
|
||||
public class LeetCode209 {
|
||||
|
||||
/**
|
||||
* 暴力求解,会超时
|
||||
* @param target
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int minSubArrayLen(int target, int[] nums) {
|
||||
|
||||
int minLength = Integer.MAX_VALUE;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
int sum = 0;
|
||||
for (int j = i; j < nums.length; j++) {
|
||||
sum += nums[j];
|
||||
if (sum >= target) {
|
||||
minLength = Math.min(minLength, j - i + 1);
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* if (sum >= target && j - i +1 < minLength) {
|
||||
* minLength = j - i + 1;
|
||||
* break;
|
||||
* }
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return minLength == Integer.MAX_VALUE ? 0 : minLength;
|
||||
}
|
||||
|
||||
public int minSubArrayLen1(int target, int[] nums) {
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
int sum = 0;
|
||||
int ans = Integer.MAX_VALUE;
|
||||
while (right < nums.length ) {
|
||||
sum += nums[right];
|
||||
// 窗口内,找到最小子串
|
||||
while (sum >= target) {
|
||||
ans = Math.min(ans, right - left + 1);
|
||||
sum -= nums[left++];
|
||||
}
|
||||
right++;
|
||||
}
|
||||
return ans == Integer.MAX_VALUE ? 0 : ans;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 前缀和做法
|
||||
* @param target
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int minSubArrayLen(int target, int[] nums) {
|
||||
// 求前缀和
|
||||
int length = nums.length;
|
||||
int[] preSum = new int[length + 1];
|
||||
for (int i = 1; i < preSum.length; i++) {
|
||||
preSum[i] = preSum[i - 1] + nums[i - 1];
|
||||
}
|
||||
// 2,3,1,2,4,3
|
||||
// 因为每个元素都是正数,所以preSum是递增的,可以用二分查找
|
||||
int minLengthFillSolution = Integer.MAX_VALUE;
|
||||
for (int i = 1; i < preSum.length; i++) {
|
||||
// 从0开始查找
|
||||
int fill = target + preSum[i - 1];
|
||||
int intervalEnd = Arrays.binarySearch(preSum, fill); // 没找到就会返回负数
|
||||
if (intervalEnd < 0) {
|
||||
intervalEnd = -intervalEnd - 1; // 防止查出来的是负数
|
||||
}
|
||||
// 这个区间如果合理,就可能是正常的区间
|
||||
if (intervalEnd <= length)
|
||||
minLengthFillSolution = Math.min(minLengthFillSolution, intervalEnd - (i - 1));
|
||||
// 注意区分下标 intervalEnd和i-1 前缀和为fill和target
|
||||
}
|
||||
return minLengthFillSolution == Integer.MAX_VALUE ? 0 : minLengthFillSolution;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void list() {
|
||||
System.out.println(new Solution().minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3}));
|
||||
|
||||
// System.out.println(minSubArrayLen1(5, new int[]{2,3,6}));
|
||||
}
|
||||
|
||||
}
|
@ -1,518 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class LeetCode215 {
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException {
|
||||
String name = "/Users/kyriewhluo/IdeaProjects/tsf/tsf-dispatch/src/main/resources/tsf-dispatch.yml";
|
||||
// 读取每一行
|
||||
HashMap<String, List<String>> map = new HashMap<>();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(name))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains("tsf-resource")) {
|
||||
String[] split = line.split("/");
|
||||
String key = "/" + split[1] + "/" + split[2];
|
||||
List<String> orDefault = map.getOrDefault(key, new ArrayList<>());
|
||||
orDefault.add(line);
|
||||
map.put(key, orDefault);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
map.forEach(new BiConsumer<String, List<String>>() {
|
||||
@Override
|
||||
public void accept(String s, List<String> strings) {
|
||||
System.out.println("# key:" + s);
|
||||
System.out.println("# size:" + strings.size());
|
||||
for (String string : strings) {
|
||||
System.out.println(string);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void sort_EmptyArray_ShouldHandleGracefull3y() {
|
||||
int[] nums = {3,2,1,5,6,4};
|
||||
System.out.println(new Solution5().findKthLargest(nums, 2));
|
||||
System.out.println(Arrays.toString(nums));
|
||||
|
||||
}
|
||||
|
||||
class Solution5 {
|
||||
|
||||
/**
|
||||
* 快速排序,某次base放对位置后,左边刚刚好有k-1个,就找到了
|
||||
* @param nums
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public int findKthLargest(int[] nums, int k) {
|
||||
return sort(nums, 0, nums.length - 1, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速排序思路,对前n-1个进行不断交换,最后把基准替换到交接点
|
||||
* @param nums
|
||||
* @param start
|
||||
* @param end
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public int sort(int[] nums, int start, int end, int k) {
|
||||
|
||||
if (start > end) {
|
||||
return nums[end];
|
||||
}
|
||||
|
||||
int q = new Random().nextInt(end - start + 1) + start;
|
||||
|
||||
swap(nums, q, end);
|
||||
|
||||
int base = nums[end];
|
||||
int left = start;
|
||||
int right = end;
|
||||
while (left < right) {
|
||||
|
||||
//从左往右遍历,当左指针指向的元素小于等于基数时,i++。左指针持续向右移动
|
||||
while (nums[left] >= base && left < right) {
|
||||
left++;
|
||||
}
|
||||
//从右往左遍历,当右指针指向的元素大于等于基数时,j--。右指针持续向左移动
|
||||
while (nums[right] <= base && left < right) {
|
||||
right--;
|
||||
}
|
||||
if (left < right) {
|
||||
//当左右两个指针停下来时,交换两个元素
|
||||
swap(nums, left, right);
|
||||
}
|
||||
}
|
||||
swap(nums, left, end);
|
||||
|
||||
// 从大到小排序,如果左边k-1个,则left就是第k个,左边k-1个比他大
|
||||
if (left == k - 1) {
|
||||
return nums[left];
|
||||
}
|
||||
// 左边的数量太少了,往右边找
|
||||
if (left < k - 1) {
|
||||
return sort(nums, left + 1, end, k);
|
||||
}
|
||||
return sort(nums, start, left - 1, k);
|
||||
|
||||
}
|
||||
public void swap(int[] heap, int start, int end) {
|
||||
int temp = heap[start];
|
||||
heap[start] = heap[end];
|
||||
heap[end] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void sort_EmptyArray_ShouldHandleGracefully8() {
|
||||
|
||||
// [3,2,3,1,2,4,5,5,6], k = 4
|
||||
int[] nums = {5,4,3,2,1};
|
||||
System.out.println(new Solution4().findKthLargest(nums, 2));
|
||||
}
|
||||
|
||||
class Solution4 {
|
||||
public int findKthLargest(int[] nums, int k) {
|
||||
for (int i = nums.length - 1; i > 0; i--) {
|
||||
shiftUp(nums, i);
|
||||
}
|
||||
System.out.println(Arrays.toString(nums));
|
||||
return nums[nums.length - k];
|
||||
}
|
||||
|
||||
public void shiftUp(int[] heap, int end) {
|
||||
int parent = (end - 1) / 2;
|
||||
while (parent >= 0) {
|
||||
int left = parent * 2 + 1;
|
||||
int right = parent * 2 + 2;
|
||||
int k = parent;
|
||||
if (left <= end &&heap[left] > heap[k]) {
|
||||
k = left;
|
||||
}
|
||||
if (right <= end && heap[right] > heap[k]) {
|
||||
k = right;
|
||||
}
|
||||
swap(heap, parent, k);
|
||||
parent--;
|
||||
}
|
||||
swap(heap, 0, end);
|
||||
}
|
||||
|
||||
public void swap(int[] heap, int start, int end) {
|
||||
int temp = heap[start];
|
||||
heap[start] = heap[end];
|
||||
heap[end] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void main()
|
||||
{
|
||||
int i = 0;
|
||||
while (true) {
|
||||
i++;
|
||||
}
|
||||
//
|
||||
// int[] nums = {3,2,1,5,6,4};
|
||||
// int k = 2;
|
||||
// Solution solution = new Solution();
|
||||
// int i = solution.findKthLargest(nums, k);
|
||||
// System.out.println(i);
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void test188()
|
||||
// {
|
||||
// new sol().findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 3);
|
||||
//
|
||||
//
|
||||
// }
|
||||
|
||||
// class sol{
|
||||
// /**
|
||||
// * 3
|
||||
// * / \
|
||||
// * / \
|
||||
// * 5 -2147483648
|
||||
// * /
|
||||
// * 2 右边那个有问题,所以不行
|
||||
// * @param nums
|
||||
// * @param k
|
||||
// * @return
|
||||
// */
|
||||
// public int findKthLargest(int[] nums, int k) {
|
||||
// Heap heap = new Heap(k);
|
||||
// for (int num : nums) {
|
||||
// heap.add(num);
|
||||
// }
|
||||
// return 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// class Heap{
|
||||
//
|
||||
//
|
||||
// int[] heap = null;
|
||||
//
|
||||
// public Heap(int k) {
|
||||
// this.heap = new int[k + 1];
|
||||
// Arrays.fill(this.heap, Integer.MIN_VALUE);
|
||||
// }
|
||||
//
|
||||
// public void add(int num) {
|
||||
// heap[heap.length - 1] = num;
|
||||
// shiftUp(heap, heap.length - 1);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 固定长度的,让其 shiftUp
|
||||
// * @param nums
|
||||
// * @param numIndex 将 numsIndex 位置上移
|
||||
// */
|
||||
// public void shiftUp(int[] nums, int numIndex) {
|
||||
// int k = numIndex;
|
||||
// while (k > 0) {
|
||||
// int parent = (k - 1) / 2;
|
||||
//// if (nums[numIndex] < nums[parent]) { // 小顶堆
|
||||
// if (nums[k] > nums[parent]) { // 大顶堆
|
||||
// // 小顶堆,小的上移
|
||||
// swap(nums, parent, k);
|
||||
// k = parent;
|
||||
// }else {
|
||||
// break;
|
||||
// }
|
||||
// TreeNode.constructTreeByArrayWithInteger(nums);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public void swap(int[] nums, int start, int end) {
|
||||
// int temp = nums[start];
|
||||
// nums[start] = nums[end];
|
||||
// nums[end] = temp;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
class Solution {
|
||||
public int findKthLargest(int[] nums, int k) {
|
||||
|
||||
|
||||
// 小顶堆
|
||||
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1 - o2;
|
||||
}
|
||||
});
|
||||
for (int num : nums) {
|
||||
priorityQueue.offer(num);
|
||||
if (priorityQueue.size() > k) {
|
||||
priorityQueue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
return priorityQueue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1()
|
||||
{
|
||||
|
||||
int[] nums = {3,2,1,5,6,4};
|
||||
int k = 2;
|
||||
Solution1 solution = new Solution1();
|
||||
int i = solution.findKthLargest(nums, k);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public int findKthLargest(int[] nums, int k) {
|
||||
sort(nums, nums.length - 1);
|
||||
|
||||
return nums[k - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 堆排序思路:
|
||||
* 1. 依次遍历非叶节点 nonLeaf = (end - 1) / 2; --
|
||||
* 选取左右两边比他大的替换上来,不断替换直到最上面是最大的
|
||||
* 2. 把最大的堆顶移动到最后,确定一个最大值
|
||||
* @param nums
|
||||
* @param end
|
||||
*/
|
||||
public void sort(int[] nums, int end) {
|
||||
if (end <= 0) {
|
||||
return;
|
||||
}
|
||||
int heapSize = nums.length;
|
||||
for (int i = heapSize / 2; i >= 0; --i) {
|
||||
int l = i * 2 + 1, r = i * 2 + 2, largest = i;
|
||||
if (l < heapSize && nums[l] > nums[largest]) {
|
||||
largest = l;
|
||||
}
|
||||
if (r < heapSize && nums[r] > nums[largest]) {
|
||||
largest = r;
|
||||
}
|
||||
if (largest != i) {
|
||||
swap(nums, i, largest);
|
||||
sort(nums, heapSize - 1);
|
||||
}
|
||||
}
|
||||
swap(nums, 0, end);
|
||||
}
|
||||
|
||||
public void swap(int[] nums, int start, int end) {
|
||||
int temp = nums[start];
|
||||
nums[start] = nums[end];
|
||||
nums[end] = temp;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void sort_EmptyArray_ShouldHandleGracefully() {
|
||||
int[] nums = {};
|
||||
sort(nums);
|
||||
assertArrayEquals(new int[0], nums);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sort_NaturalNumberArray_ShouldSortInAscendingOrder() {
|
||||
int[] nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
|
||||
sort(nums);
|
||||
assertArrayEquals(new int[]{1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9}, nums);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sort_IntegerArray_ShouldSortInAscendingOrder() {
|
||||
int[] nums = {10, -1, 2, 5, 0, 6, -3, 4};
|
||||
sort(nums);
|
||||
assertArrayEquals(new int[]{-3, -1, 0, 2, 4, 5, 6, 10}, nums);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sort_SingleElementArray_ShouldRemainUnchanged() {
|
||||
int[] nums = {5};
|
||||
sort(nums);
|
||||
assertArrayEquals(new int[]{5}, nums);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sort_DuplicateElementsArray_ShouldSortInAscendingOrder() {
|
||||
int[] nums = {4, 2, 2, 8, 3, 3, 1};
|
||||
sort(nums);
|
||||
assertArrayEquals(new int[]{1, 2, 2, 3, 3, 4, 8}, nums);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sort_NegativeNumberArray_ShouldSortInAscendingOrder() {
|
||||
int[] nums = {-1, -2, -3, -4, -5};
|
||||
System.out.println(Arrays.toString(new Solution3().sortArray(nums)));
|
||||
}
|
||||
|
||||
class Solution3 {
|
||||
public int[] sortArray(int[] nums) {
|
||||
sort(nums, nums.length - 1);
|
||||
return nums;
|
||||
}
|
||||
|
||||
/**
|
||||
* 堆排序思路:
|
||||
* 1. 依次遍历非叶节点 nonLeaf = (end - 1) / 2; --
|
||||
* 选取左右两边比他大的替换上来,不断替换直到最上面是最大的
|
||||
* 2. 把最大的堆顶移动到最后,确定一个最大值
|
||||
* @param nums
|
||||
* @param end
|
||||
*/
|
||||
public void sort(int[] nums, int end) {
|
||||
if (end <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int nonLeaf = (end - 1) / 2;
|
||||
while (nonLeaf >= 0) {
|
||||
|
||||
|
||||
int left = 2 * nonLeaf + 1;
|
||||
int right = 2 * nonLeaf + 2;
|
||||
|
||||
|
||||
int maxIn = nonLeaf; // 父子三个节点的最大值
|
||||
if (left <= end && nums[maxIn] < nums[left]) {
|
||||
maxIn = left;
|
||||
}
|
||||
if (right <= end && nums[maxIn] < nums[right]) {
|
||||
maxIn = right;
|
||||
}
|
||||
swap(nums, nonLeaf, maxIn);
|
||||
|
||||
|
||||
|
||||
// // noleaf至少有一个子节点
|
||||
// if (left <= end &&right <= end) {
|
||||
// if (nums[left] < nums[right]) {
|
||||
// if (nums[right] > nums[nonLeaf]) {
|
||||
// swap(nums, nonLeaf, right);
|
||||
// }
|
||||
// }else {
|
||||
// if (nums[left] > nums[nonLeaf]) {
|
||||
// swap(nums, nonLeaf, left);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // 只有左边一个节点
|
||||
// if (nums[left] > nums[nonLeaf]) {
|
||||
// swap(nums, nonLeaf, left);
|
||||
// }
|
||||
// }
|
||||
nonLeaf--;
|
||||
}
|
||||
swap(nums, 0, end );
|
||||
sort(nums, end - 1);
|
||||
}
|
||||
|
||||
public void swap(int[] nums, int start, int end) {
|
||||
int temp = nums[start];
|
||||
nums[start] = nums[end];
|
||||
nums[end] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 所有非叶子节点x(自 n/2 开始,表示下面都是叶子节点)找到子节点中的最大值,如果比x 还大,swap。再排序下一个非叶子节点
|
||||
*/
|
||||
public void sort(int[] nums) {
|
||||
sort(nums, nums.length - 1);
|
||||
System.out.println(Arrays.toString(nums));
|
||||
}
|
||||
|
||||
/**
|
||||
* 堆排序思路:
|
||||
* 1. 依次遍历非叶节点 nonLeaf = (end - 1) / 2; --
|
||||
* 选取左右两边比他大的替换上来,不断替换直到最上面是最大的
|
||||
* 2. 把最大的堆顶移动到最后,确定一个最大值
|
||||
* @param nums
|
||||
* @param end
|
||||
*/
|
||||
public void sort(int[] nums, int end) {
|
||||
if (end <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int nonLeaf = (end - 1) / 2;
|
||||
while (nonLeaf >= 0) {
|
||||
|
||||
|
||||
int left = 2 * nonLeaf + 1;
|
||||
int right = 2 * nonLeaf + 2;
|
||||
|
||||
|
||||
int maxIn = nonLeaf; // 父子三个节点的最大值
|
||||
if (left <= end && nums[maxIn] < nums[left]) {
|
||||
maxIn = left;
|
||||
}
|
||||
if (right <= end && nums[maxIn] < nums[right]) {
|
||||
maxIn = right;
|
||||
}
|
||||
swap(nums, nonLeaf, maxIn);
|
||||
|
||||
|
||||
|
||||
// // noleaf至少有一个子节点
|
||||
// if (left <= end &&right <= end) {
|
||||
// if (nums[left] < nums[right]) {
|
||||
// if (nums[right] > nums[nonLeaf]) {
|
||||
// swap(nums, nonLeaf, right);
|
||||
// }
|
||||
// }else {
|
||||
// if (nums[left] > nums[nonLeaf]) {
|
||||
// swap(nums, nonLeaf, left);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // 只有左边一个节点
|
||||
// if (nums[left] > nums[nonLeaf]) {
|
||||
// swap(nums, nonLeaf, left);
|
||||
// }
|
||||
// }
|
||||
nonLeaf--;
|
||||
}
|
||||
swap(nums, 0, end );
|
||||
sort(nums, end - 1);
|
||||
}
|
||||
|
||||
public void swap(int[] nums, int start, int end) {
|
||||
int temp = nums[start];
|
||||
nums[start] = nums[end];
|
||||
nums[end] = temp;
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousFileChannel;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/22 14:56
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode228 {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("D:\\project\\LeetCode\\README.md"), StandardOpenOption.READ);
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||
Future<Integer> result = fileChannel.read(buffer, 0);
|
||||
while (!result.isDone()) {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {0, 2};
|
||||
System.out.println(new Solution().summaryRanges(nums));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
// public List<String> summaryRanges(int[] nums) {
|
||||
// List<String> path = new ArrayList<>();
|
||||
// List<String> res = new ArrayList<>();
|
||||
// for (int i = 1; i < nums.length; i++) {
|
||||
// if (nums[i] != nums[i - 1]) {
|
||||
// StringBuilder str = new StringBuilder();
|
||||
// for (int j = 0; j < path.size()-1; j++) {
|
||||
// str.append(path.get(j));
|
||||
// str.append("->");
|
||||
// }
|
||||
// str.append(path.get(path.size() - 1));
|
||||
// path.clear();
|
||||
// }
|
||||
// path.add(String.valueOf(nums[i]));
|
||||
// }
|
||||
// }
|
||||
public List<String> summaryRanges(int[] nums) {
|
||||
|
||||
|
||||
List<String> res = new ArrayList<>();
|
||||
|
||||
int left = 0;
|
||||
int right = 1;
|
||||
while (right < nums.length) {
|
||||
if (nums[right] != nums[right - 1] + 1) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(nums[left]);
|
||||
if (left != right - 1) {
|
||||
stringBuilder.append("->");
|
||||
stringBuilder.append(nums[right - 1]);
|
||||
}
|
||||
res.add(stringBuilder.toString());
|
||||
left = right;
|
||||
}
|
||||
right++;
|
||||
}
|
||||
if (left < nums.length) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(nums[left]);
|
||||
if (left != right - 1) {
|
||||
stringBuilder.append("->");
|
||||
stringBuilder.append(nums[right - 1]);
|
||||
}
|
||||
res.add(stringBuilder.toString());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/17 13:58
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode238 {
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1, 2, 3, 4};
|
||||
int[] ints = productExceptSelf(nums);
|
||||
for (int anInt : ints) {
|
||||
System.out.println(anInt);
|
||||
}
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* [-1,1,0,-3,3]
|
||||
* -1 -1 0 0 0
|
||||
* 0 0 0 -9 3
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int[] productExceptSelf(int[] nums) {
|
||||
int[] preMul = new int[nums.length];
|
||||
preMul[0] = nums[0];
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
preMul[i] = preMul[i - 1] * nums[i];
|
||||
}
|
||||
|
||||
int[] afterMul = new int[nums.length];
|
||||
afterMul[nums.length - 1] = nums[nums.length - 1];
|
||||
for (int i = nums.length - 2; i >= 0; i--) {
|
||||
afterMul[i] = afterMul[i + 1] * nums[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
int pre = (i > 0) ? preMul[i - 1] : 1;
|
||||
int after = i < nums.length - 1 ? afterMul[i + 1] : 1;
|
||||
nums[i] = pre * after;
|
||||
}
|
||||
|
||||
return nums;
|
||||
}
|
||||
}
|
||||
|
||||
//维护两个变量,beforeSum表示前缀和,afterSum表示后缀和
|
||||
// 两个指针不断缩小会相交
|
||||
public int[] productExceptSelf(int[] nums) {
|
||||
int n = nums.length;
|
||||
int[] ans = new int[n];
|
||||
Arrays.fill(ans, 1);
|
||||
int beforeSum = 1;
|
||||
int afterSum = 1;
|
||||
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
while (left < nums.length) {
|
||||
ans[left] *= beforeSum;
|
||||
ans[right] *= afterSum;
|
||||
beforeSum *= nums[left];
|
||||
afterSum *= nums[right];
|
||||
left++;
|
||||
right--;
|
||||
}
|
||||
|
||||
return ans;
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 删除有序数组中的重复项
|
||||
* 简单
|
||||
* 相关标签
|
||||
* 相关企业
|
||||
* 提示
|
||||
* 给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
|
||||
*
|
||||
* 考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:
|
||||
*
|
||||
* 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
|
||||
* 返回 k 。
|
||||
* 判题标准:
|
||||
*
|
||||
* 系统会用下面的代码来测试你的题解:
|
||||
*
|
||||
* int[] nums = [...]; // 输入数组
|
||||
* int[] expectedNums = [...]; // 长度正确的期望答案
|
||||
*
|
||||
* int k = removeDuplicates(nums); // 调用
|
||||
*
|
||||
* assert k == expectedNums.length;
|
||||
* for (int i = 0; i < k; i++) {
|
||||
* assert nums[i] == expectedNums[i];
|
||||
* }
|
||||
* 如果所有断言都通过,那么您的题解将被 通过。
|
||||
*
|
||||
*
|
||||
*
|
||||
* 示例 1:
|
||||
*
|
||||
* 输入:nums = [1,1,2]
|
||||
* 输出:2, nums = [1,2,_]
|
||||
* 解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:nums = [0,0,1,1,1,2,2,3,3,4]
|
||||
* 输出:5, nums = [0,1,2,3,4]
|
||||
* 解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
|
||||
*
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 1 <= nums.length <= 3 * 104
|
||||
* -104 <= nums[i] <= 104
|
||||
* nums 已按 非严格递增 排列
|
||||
*/
|
||||
public class LeetCode26 {
|
||||
|
||||
public int removeDuplicates(int[] nums) {
|
||||
// 保证return k 的k nums 前k个为唯一递增的
|
||||
int left = 0; // 左指针,指向无重复元素数组的起始位置
|
||||
int right = 1; // 右指针,指向当前元素数组的位置
|
||||
while (right < nums.length) {
|
||||
if (nums[right] == nums[left]) { // 如果右指针指向的元素等于左指针指向的元素
|
||||
right++; // 则右指针向右移动
|
||||
} else {
|
||||
nums[++left] = nums[right++]; // 若不相等,则将当前元素放入无重复元素数组中,并同时将左指针和右指针向右移动
|
||||
}
|
||||
}
|
||||
return left + 1; // 返回无重复元素数组的长度
|
||||
}
|
||||
|
||||
public int removeDuplicates1(int[] nums) {
|
||||
// 保证return k 的k nums 前k个为唯一递增的
|
||||
int left = 0;
|
||||
int right = 1;
|
||||
int jump = 0;
|
||||
while (right < nums.length) {
|
||||
if (nums[right] == nums[left]) {
|
||||
right++;
|
||||
jump++;
|
||||
} else {
|
||||
nums[left + 1] = nums[right];
|
||||
right++;
|
||||
left++;
|
||||
}
|
||||
}
|
||||
return left + 1;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(removeDuplicates(new int[]{1,1,2}));
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/28 16:59
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode2602 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
Solution solution = new Solution();
|
||||
int[] nums = {3,1,6,8};
|
||||
int[] queries = {1,5};
|
||||
List<Long> res = solution.minOperations(nums, queries);
|
||||
res.forEach(System.out::println);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 超时
|
||||
*/
|
||||
class Solution {
|
||||
public List<Long> minOperations(int[] nums, int[] queries) {
|
||||
List<Long> res = new ArrayList<>();
|
||||
for (int query : queries) {
|
||||
res.add(target(nums, query));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public long target(int[] nums, int target) {
|
||||
|
||||
long res = 0;
|
||||
for (int num : nums) {
|
||||
res += Math.abs(target - num);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public List<Long> minOperations(int[] nums, int[] queries) {
|
||||
List<Long> res = new ArrayList<>();
|
||||
Arrays.sort(nums);
|
||||
// 排序后,找到对应的元素,左边小于,右边大于
|
||||
// 求前缀和
|
||||
int length = nums.length;
|
||||
long[] preSum = new long[length + 1];
|
||||
for (int i = 0; i < length; i++) {
|
||||
preSum[i + 1] = preSum[i] + nums[i];
|
||||
}
|
||||
|
||||
for (int target : queries) {
|
||||
int index = findIndex(nums, target);
|
||||
long left = (long) index * target - preSum[index];
|
||||
// index 为横坐标 target为纵坐标高度 preSum为index位置前面的总和
|
||||
long right = preSum[length] - preSum[index] - (long) target * (length - index);
|
||||
res.add(left + right);
|
||||
}
|
||||
|
||||
// 一侧的前缀和与 “平均值*一侧区间长度” 就代表这一侧的总操作数
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
public int findIndex(int[] nums, int target) {
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
while (left <= right) {
|
||||
int mid = left + (right - left) / 2;
|
||||
if (nums[mid] == target) {
|
||||
return mid;
|
||||
} else if (nums[mid] > target) {
|
||||
right = mid - 1;
|
||||
} else {
|
||||
left = mid + 1;
|
||||
}
|
||||
}
|
||||
return right;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1()
|
||||
{
|
||||
Solution2 solution2 = new Solution2();
|
||||
int[] nums = {3,1,6,8};
|
||||
int[] queries = {5};
|
||||
List<Long> res = solution2.minOperations(nums, queries);
|
||||
res.forEach(System.out::println);
|
||||
}
|
||||
|
||||
|
||||
class Solution2 {
|
||||
public List<Long> minOperations(int[] nums, int[] queries) {
|
||||
Arrays.sort(nums);
|
||||
|
||||
// 计算前缀和
|
||||
long[] preSum = new long[nums.length + 1];
|
||||
for (int i = 1; i < preSum.length; i++) {
|
||||
preSum[i] = preSum[i - 1] + nums[i - 1];
|
||||
}
|
||||
|
||||
List<Long> res = new ArrayList<>();
|
||||
for (int query : queries) {
|
||||
res.add(getOperation(nums, query, preSum));
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <img src="http://42.192.130.83:9000/picgo/imgs/1679808210-FVsAou-t3.png">
|
||||
* </img>
|
||||
* @param nums 原数组
|
||||
* @param target 目标
|
||||
* @param preSum 前缀和
|
||||
* @return
|
||||
*/
|
||||
public Long getOperation(int[] nums, int target,long[] preSum) {
|
||||
|
||||
int index = findIndex(nums, target);
|
||||
// index左边全部比他小、右边全部比他大
|
||||
// 0 - index 为小于他的数字个数 index-length为大于他的个数
|
||||
// 小于他的数的总和 = 小于的个数 index * (target-nums[0]) - index位置的前缀和(前缀和就是一个下三角形的面积)
|
||||
long leftIncr = (long) index * target - preSum[index];
|
||||
long rightIncr =
|
||||
preSum[nums.length] - preSum[index]
|
||||
- (long) target * (nums.length - index);
|
||||
|
||||
return leftIncr + rightIncr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 二分查找
|
||||
* @param nums 有序数组
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int findIndex(int[] nums, int target) {
|
||||
int left = 0, right = nums.length - 1;
|
||||
while (left <= right) {
|
||||
int mid = (right + left) / 2;
|
||||
if (nums[mid] < target) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
|
||||
*
|
||||
* 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
|
||||
*
|
||||
* 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
|
||||
*
|
||||
*
|
||||
*
|
||||
* 说明:
|
||||
*
|
||||
* 为什么返回数值是整数,但输出的答案是数组呢?
|
||||
*
|
||||
* 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
|
||||
*
|
||||
* 你可以想象内部操作如下:
|
||||
*
|
||||
* // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
|
||||
* int len = removeElement(nums, val);
|
||||
*
|
||||
* // 在函数里修改输入数组对于调用者是可见的。
|
||||
* // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
|
||||
* for (int i = 0; i < len; i++) {
|
||||
* print(nums[i]);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* 示例 1:
|
||||
*
|
||||
* 输入:nums = [3,2,2,3], val = 3
|
||||
* 输出:2, nums = [2,2]
|
||||
* 解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:nums = [0,1,2,2,3,0,4,2], val = 2
|
||||
* 输出:5, nums = [0,1,3,0,4]
|
||||
* 解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
|
||||
*
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 0 <= nums.length <= 100
|
||||
* 0 <= nums[i] <= 50
|
||||
* 0 <= val <= 100
|
||||
*
|
||||
* 相关题目推荐
|
||||
* 26.删除排序数组中的重复项(opens new window)
|
||||
* 283.移动零(opens new window)
|
||||
* 844.比较含退格的字符串(opens new window)
|
||||
* 977.有序数组的平方(opens new window)
|
||||
* #其他语言版本
|
||||
*
|
||||
*/
|
||||
public class LeetCode27 {
|
||||
|
||||
// public int removeElement(int[] nums, int val) {
|
||||
// int hasCount = 0;
|
||||
// int numLength = nums.length;
|
||||
// for (int i = 0; i < nums.length; i++) {
|
||||
// if (nums[i] == val) {
|
||||
// hasCount++;
|
||||
// }
|
||||
// }
|
||||
// return numLength - hasCount;
|
||||
// }
|
||||
|
||||
// 双指针
|
||||
public int removeElement(int[] nums, int val) {
|
||||
int slowIndex = 0;
|
||||
|
||||
for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
|
||||
if (nums[fastIndex] != val) {
|
||||
nums[slowIndex] = nums[fastIndex];
|
||||
slowIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return slowIndex;
|
||||
}
|
||||
@Test
|
||||
public void testSearch1() {
|
||||
|
||||
LeetCode27 leetCode27 = new LeetCode27();
|
||||
System.out.println("return" + leetCode27.removeElement(new int[]{0,1,2,2,3,0,4,2}, 2));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/16 17:17
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode274 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums = new int[]{1,3,1};
|
||||
System.out.println(new Solution().hIndex(nums));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int hIndex(int[] citations) {
|
||||
|
||||
Arrays.sort(citations);
|
||||
|
||||
for (int i = 0; i < citations.length; i++) {
|
||||
int h = citations.length - i;
|
||||
if (citations[i] >= h) {
|
||||
return h;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class LeetCode287 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution().findDuplicate(new int[]{1, 3, 3, 2}));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 将数组转换为链表思想
|
||||
* [ 1, 3, 4, 2, 2]
|
||||
* 0 1 2 3 4
|
||||
*
|
||||
* 0->1->3->[2->4->2->4->2.....]
|
||||
*
|
||||
* ListNode index = index.next
|
||||
* 等价于 int index = nums[index]
|
||||
*
|
||||
*
|
||||
* - nums.length == n + 1
|
||||
* - 1 <= nums[i] <= n
|
||||
* 表明 如果只有3个元素,取值区间只能为[1,2,3]
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int findDuplicate(int[] nums) {
|
||||
|
||||
// 因为 1 <= n <= 105 所以0只在开始出现过。
|
||||
// 两个指针
|
||||
int fast = 0;
|
||||
int slow = 0;
|
||||
slow = nums[slow];
|
||||
fast = nums[nums[fast]];
|
||||
// 找到相遇的地方
|
||||
while (fast != slow) {
|
||||
fast = nums[nums[fast]];
|
||||
slow = nums[slow];
|
||||
}
|
||||
// 此时两个指针指向同个地方,表示在环的里面
|
||||
int tmp = 0;
|
||||
while (nums[tmp] != nums[slow]) {
|
||||
tmp = nums[tmp];
|
||||
slow = nums[slow];
|
||||
}
|
||||
|
||||
return nums[tmp];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/23 11:08
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode289 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] board = new int[][]{{0, 1, 0}, {0, 0, 1}, {1, 1, 1}, {0, 0, 0}};
|
||||
new Solution().gameOfLife(board);
|
||||
for (int[] ints : board) {
|
||||
System.out.println(Arrays.toString(ints));
|
||||
}
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
* 为了保证当前修改后的状态不会影响下一个状态的判定,设置另外的状态
|
||||
* 如题所示,只有三种:
|
||||
* 1. 如果当前是活细胞,但是变成了死细胞,那么设置为-1
|
||||
* 2. 如果当前是活细胞,仍然是活细胞,那么不变仍为1
|
||||
* 3. 如果当前是死细胞,但是变成了活细胞,那么设置为2
|
||||
* 那么最后遍历修改完状态之后,将-1修改回为0,2修改回为1
|
||||
* @param board
|
||||
*/
|
||||
public void gameOfLife(int[][] board) {
|
||||
//设置方向来遍历某个节点周围的另外几个节点
|
||||
int[] ner = new int[]{-1,0,1};
|
||||
//获取行和列
|
||||
int rows = board.length;
|
||||
int cols = board[0].length;
|
||||
//遍历每一个节点格子
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
//设置当前节点周围的存活细胞的数量
|
||||
int liveNer = 0;
|
||||
/**
|
||||
* 当前节点是[ i , j ]
|
||||
* [i-1,j-1] [i-1,j] [i-1,j+1]
|
||||
* [ i ,j-1] [ i ,j] [ i ,j+1]
|
||||
* [i+1,j-1] [i+1,j] [i+1,j+1]
|
||||
* 那么以当前节点为中心,要求周围的节点,则最多是3*3形式
|
||||
* 并且所有的行和列都是用当前节点+1或者-1或者不变构成
|
||||
* 所以我们设置 ner = {-1,0,1} 来形成遍历
|
||||
*/
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
//必须保证不计算当前节点(不计算自己)
|
||||
if (!(ner[i]==0 && ner[j]==0)){
|
||||
//当前节点的相邻节点坐标
|
||||
int r = row+ner[i];
|
||||
int c = col+ner[j];
|
||||
/**判断当前周围节点的存活状态,要求满足两个状态
|
||||
* 1. 必须保证要在 board 矩阵中
|
||||
* 2. 并且**起始状态要是存活,则当前状态为1或者-1都可以(因为这两个状态都表示起始状态为活细胞)**
|
||||
**/
|
||||
if ((r >= 0 && r < rows) && (c >= 0 && c < cols) && (Math.abs(board[r][c]) == 1)) {
|
||||
// -1和1 初始状态都是活细胞
|
||||
liveNer++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**开始判断当前节点的存活状态
|
||||
* 因为遍历到当前节点的时候,还没有开始修改细胞状态,所以还是0和1的细胞状态
|
||||
* 那么只需要判断状态变化的即可,否则状态不变
|
||||
**/
|
||||
if ((board[row][col]==1) && ( liveNer>3 || liveNer<2)){
|
||||
// -1 代表这个细胞过去是活的现在死了
|
||||
board[row][col]=-1;
|
||||
}
|
||||
if (board[row][col]==0 && ( liveNer==3)){
|
||||
// 2 代表这个细胞过去是死的现在活了
|
||||
board[row][col]=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
//再把额外的状态修改回去
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (board[row][col] == 2) {
|
||||
board[row][col] = 1;
|
||||
}
|
||||
if (board[row][col] == -1){
|
||||
board[row][col] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/5 13:18
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode31 {
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {3,2,1};
|
||||
new Solution1().nextPermutation(nums);
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
System.out.print(nums[i] + " ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public void nextPermutation(int[] nums) {
|
||||
if (nums.length == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1.下一个数 比当前数大
|
||||
// 将后面的「大数」与前面的「小数」交换,就能得到更大的数
|
||||
// 2. 下一个数 增加的幅度尽可能的小
|
||||
// - 尽可能靠右的低位 进行交换
|
||||
// - 将一个 尽可能小的「大数」 与前面的「小数」交换
|
||||
// 123465 把 5和4换
|
||||
// - 「大数」后面的所有数 重置为升序
|
||||
// 123564 把5后面重新排序
|
||||
|
||||
// 1. 从后往前找到第一个升序排列,此时后面那部分一定是降序
|
||||
int i;
|
||||
for (i = nums.length - 2; i >= 0; i--) {
|
||||
if (nums[i] < nums[i + 1]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == -1) {
|
||||
// 最后一个排序 654321,直接逆转
|
||||
reverse(nums, 0, nums.length - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 从i+1开始找到最小的值
|
||||
int min;
|
||||
for (min = nums.length - 1; min > 0; min--) {
|
||||
if (nums[min] > nums[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 3. 交换i和minIndex
|
||||
swap(nums, i, min);
|
||||
// 4. 后面为降序,直接让其逆转变为升序
|
||||
reverse(nums, i + 1, nums.length - 1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void reverse(int[] nums, int start, int end) {
|
||||
while (start < end) {
|
||||
swap(nums, start, end);
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
public void swap(int[] nums, int i, int j) {
|
||||
int temp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public void nextPermutation(int[] nums) {
|
||||
if (nums.length == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = nums.length - 2;
|
||||
while (i >= 0) {
|
||||
if (nums[i] < nums[i + 1]) {
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i == -1) {
|
||||
// 最后一个排序 654321,直接逆转
|
||||
reverse(nums, 0, nums.length - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
int min = nums.length - 1;
|
||||
while (min > 0) {
|
||||
if (nums[min] > nums[i]) {
|
||||
break;
|
||||
}
|
||||
min--;
|
||||
}
|
||||
|
||||
|
||||
// 3. 交换i和minIndex
|
||||
swap(nums, i, min);
|
||||
// 4. 后面为降序,直接让其逆转变为升序
|
||||
reverse(nums, i + 1, nums.length - 1);
|
||||
}
|
||||
|
||||
public void reverse(int[] nums, int start, int end) {
|
||||
while (start < end) {
|
||||
swap(nums, start, end);
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
public void swap(int[] nums, int i, int j) {
|
||||
int temp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
class ass extends as{
|
||||
|
||||
@Override
|
||||
public void test() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void test1() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void test2() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class as{
|
||||
|
||||
abstract public void test() ;
|
||||
|
||||
abstract void test1();
|
||||
|
||||
abstract protected void test2();
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/15 10:32
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode33 {
|
||||
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums = new int[]{4, 5, 6, 7, 0, 1, 2};
|
||||
int target = 0;
|
||||
int i = new Solution().search(nums, target);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
*
|
||||
* @param nums 旋转后的值
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int search(int[] nums, int target) {
|
||||
|
||||
// 二分查找,关键在于如何找到两个递增区间的交结处k
|
||||
// 判断left和mid的关系
|
||||
// 如果nums[left] < nums[mid] 即mid在left-k的区间
|
||||
// if(target<nums[mid] && target>nums[left]) 在left到mid区间
|
||||
// else mid到right区间
|
||||
// 如果nums[left] > nums[mid] 即mid在k-right的区间
|
||||
// if(target>nums[mid]&&target<nums[right]) mid到right之间
|
||||
// else left到mid之间
|
||||
int left = 0, right = nums.length - 1;
|
||||
|
||||
|
||||
while (left <= right) {
|
||||
int mid = (left + right) / 2;
|
||||
if (nums[mid] == target) {
|
||||
return mid;
|
||||
}
|
||||
if (nums[left] <= nums[mid] ) {
|
||||
if (target < nums[mid] && target >= nums[left]) {
|
||||
right = mid - 1;
|
||||
} else {
|
||||
left = mid + 1;
|
||||
}
|
||||
} else {
|
||||
if (target > nums[mid] && target <= nums[right]) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
}
|
||||
//
|
||||
// class Solution1 {
|
||||
// public int search(int[] nums, int target) {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 34. 在排序数组中查找元素的第一个和最后一个位置
|
||||
* 中等
|
||||
* 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
|
||||
*
|
||||
* 如果数组中不存在目标值 target,返回 [-1, -1]。
|
||||
*
|
||||
* 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
|
||||
* 示例 1:
|
||||
*
|
||||
* 输入:nums = [5,7,7,8,8,10], target = 8
|
||||
* 输出:[3,4]
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:nums = [5,7,7,8,8,10], target = 6
|
||||
* 输出:[-1,-1]
|
||||
* 示例 3:
|
||||
*
|
||||
* 输入:nums = [], target = 0
|
||||
* 输出:[-1,-1]
|
||||
*
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 0 <= nums.length <= 105
|
||||
* -109 <= nums[i] <= 109
|
||||
* nums 是一个非递减数组
|
||||
* -109 <= target <= 109
|
||||
*/
|
||||
public class LeetCode34 {
|
||||
/**
|
||||
* 非递减顺序排列的整数数组
|
||||
* [0,length]
|
||||
* [5,8,8,8,8,10]
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int[] searchRange(int[] nums, int target) {
|
||||
int[] ans = new int[2];
|
||||
// 三头
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
while (left <= right) {
|
||||
int middle = (left + right) / 2;
|
||||
if (nums[middle] == target) {
|
||||
// 在[left,middle) , (middle,right]区间里找到第一个和最后一个target
|
||||
|
||||
// break;
|
||||
// 找到了一个
|
||||
if (nums[left] == target && nums[right] == target) {
|
||||
ans[0] = left;
|
||||
ans[1] = right;
|
||||
return ans;
|
||||
} else if (nums[left] == target) {
|
||||
right--;
|
||||
} else if (nums[right] == target) {
|
||||
left++;
|
||||
} else {
|
||||
right--;
|
||||
left++;
|
||||
}
|
||||
} else if (nums[middle] < target) {
|
||||
left = middle + 1;
|
||||
} else {
|
||||
right = middle - 1;
|
||||
}
|
||||
}
|
||||
ans[0] = -1;
|
||||
ans[1] = -1;
|
||||
return ans;
|
||||
}
|
||||
public int[] searchRange2(int[] nums, int target) {
|
||||
int leftIdx = binarySearch(nums, target, true);
|
||||
int rightIdx = binarySearch(nums, target, false) - 1;
|
||||
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
|
||||
return new int[]{leftIdx, rightIdx};
|
||||
}
|
||||
return new int[]{-1, -1};
|
||||
}
|
||||
|
||||
public int binarySearch(int[] nums, int target, boolean lower) {
|
||||
int left = 0, right = nums.length - 1, ans = nums.length;
|
||||
while (left <= right) {
|
||||
int mid = (left + right) / 2;
|
||||
if (nums[mid] > target || (lower && nums[mid] >= target)) {
|
||||
right = mid - 1;
|
||||
ans = mid;
|
||||
} else {
|
||||
left = mid + 1;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
for (int i : searchRange2(new int[]{5,8,8,8,8,10}, 8)) {
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
|
||||
* 请必须使用时间复杂度为 O(log n) 的算法。
|
||||
*
|
||||
* 示例 1:
|
||||
* 输入: nums = [1,3,5,6], target = 5
|
||||
* 输出: 2
|
||||
* 示例 2:
|
||||
* 输入: nums = [1,3,5,6], target = 2
|
||||
* 输出: 1
|
||||
* 示例 3:
|
||||
* 输入: nums = [1,3,5,6], target = 7
|
||||
* 输出: 4
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 1 <= nums.length <= 104
|
||||
* -104 <= nums[i] <= 104
|
||||
* nums 为 无重复元素 的 升序 排列数组
|
||||
* -104 <= target <= 104
|
||||
*/
|
||||
public class LeetCode35 {
|
||||
|
||||
/**
|
||||
* left左边的值一直保持小于target,right右边的值一直保持大于等于target,
|
||||
* 而且left最终一定等于right+1,
|
||||
* 这么一来,循环结束后,
|
||||
* 在left和right之间画一条竖线,恰好可以把数组分为两部分:
|
||||
* left左边的部分和right右边的部分,而且left左边的部分全部小于target,并以right结尾;
|
||||
* right右边的部分全部大于等于target,并以left为首。
|
||||
*
|
||||
* 所以最终答案一定在left的位置。
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int searchInsert(int[] nums, int target) {
|
||||
// 定义左右指针,分别指向数组的起始位置和结束位置
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
// 当左指针小于等于右指针时,进行循环
|
||||
while (left <= right) {
|
||||
// 计算中间位置的索引 右边距减去左边距,右移一位,然后加上左边距,得到中间值
|
||||
// right-left 就是从0开始到n, 右移动一位就是除以2,获得到这个区间的一半,加上起始的left 就是(right + left)/2
|
||||
int middle = ((right - left) >> 1) + left;
|
||||
// 如果中间位置的元素等于目标元素,返回中间位置的索引
|
||||
if (nums[middle] == target) {
|
||||
return middle;
|
||||
// 如果中间位置的元素大于目标元素,将右指针移动到中间位置的左侧一个位置
|
||||
} else if (nums[middle] > target) {
|
||||
right = middle - 1;
|
||||
// 如果中间位置的元素小于目标元素,将左指针移动到中间位置的右侧一个位置
|
||||
} else {
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
// 当找不到目标元素时,返回左指针的值
|
||||
return left;
|
||||
}
|
||||
|
||||
|
||||
public int searchInsert1(int[] nums, int target) {
|
||||
int left = 0;
|
||||
int right = nums.length;
|
||||
while (left < right) {
|
||||
int middle = (right + left) / 2;
|
||||
if (nums[middle] == target) {
|
||||
return middle;
|
||||
} else if (nums[middle] > target) {
|
||||
right = middle ;
|
||||
} else {
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void Test() {
|
||||
int[] ints = {1, 3, 5, 8,10};
|
||||
int[] ints1 = {};
|
||||
|
||||
int middle = ((8 - 4) >> 1) + 4;
|
||||
|
||||
// 1000 - 0100 = 0100 >> 1 = 0010 ==> 2 + 4
|
||||
System.out.println(searchInsert1(ints, 2));
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* 给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
|
||||
* 完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。
|
||||
* 不能使用任何内置的库函数,如 sqrt 。
|
||||
*
|
||||
* 示例 1:
|
||||
*
|
||||
* 输入:num = 16
|
||||
* 输出:true
|
||||
* 解释:返回 true ,因为 4 * 4 = 16 且 4 是一个整数。
|
||||
*
|
||||
*
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:num = 14
|
||||
* 输出:false
|
||||
* 解释:返回 false ,因为 3.742 * 3.742 = 14 但 3.742 不是一个整数。
|
||||
*
|
||||
* 提示:
|
||||
* 1 <= num <= 231 - 1
|
||||
*/
|
||||
public class LeetCode367 {
|
||||
|
||||
/**
|
||||
* 时间复杂度:O(logn)
|
||||
* 空间复杂度:O(1)
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
public boolean isPerfectSquare(int num) {
|
||||
int left = 0;
|
||||
int right = num;
|
||||
while (left <= right) {
|
||||
int middle = (left + right) / 2;
|
||||
if (middle * middle == num) {
|
||||
return true;
|
||||
} else if ((long) middle * middle > num) {
|
||||
right = middle - 1;
|
||||
// rigjt--;
|
||||
} else {
|
||||
// 如果middle * middle < num ,那么 寻找的区间就应该是 xx,middle) 或者说middle*middle 这个数太大了
|
||||
// left++;
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 代码中使用的 pow\texttt{pow}pow 函数的时空复杂度与 CPU 支持的指令集相关,这里不深入分析。
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
public boolean isPerfectSquare1(int num) {
|
||||
double sqrt = Math.sqrt(num);
|
||||
// 判断有没有小数
|
||||
if (sqrt == (int) sqrt) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间复杂度:On
|
||||
* 空间复杂 O1
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
public boolean isPerfectSquare2(int num) {
|
||||
// 暴力
|
||||
for (int i = 1; i <= num; i++) {
|
||||
if ((long)i * i == num) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void main() {
|
||||
LeetCode367 solution = new LeetCode367();
|
||||
|
||||
// Test case 1: num is a perfect square
|
||||
int num1 = 16;
|
||||
assertTrue(solution.isPerfectSquare1(num1));
|
||||
|
||||
// Test case 2: num is not a perfect square
|
||||
int num2 = 15;
|
||||
assertFalse(solution.isPerfectSquare1(num2));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,64 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/29 12:54
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode453 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums = {1, 1,1};
|
||||
int res = new Solution1().minMoves(nums);
|
||||
System.out.println(res);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 让n-1个元素加1 等价于让1个元素-1,直到全部元素相等
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int minMoves(int[] nums) {
|
||||
int min = Integer.MAX_VALUE;
|
||||
for (int num : nums) {
|
||||
min = Math.min(min, num);
|
||||
}
|
||||
int res = 0;
|
||||
for (int num : nums) {
|
||||
res += Math.abs(min - num);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* 让n-1个元素加1 等价于让1个元素-1,直到全部元素相等
|
||||
* 前缀和解法
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int minMoves(int[] nums) {
|
||||
|
||||
// 获取前缀和
|
||||
int length = nums.length;
|
||||
int[] preSum = new int[length + 1];
|
||||
// 找到最小的元素的index
|
||||
int minIndex = 0;
|
||||
for (int i = 1; i <= length; i++) {
|
||||
if (nums[minIndex] > nums[i - 1]) {
|
||||
minIndex = i - 1;
|
||||
}
|
||||
preSum[i] = preSum[i - 1] + nums[i - 1];
|
||||
}
|
||||
|
||||
return preSum[length] - nums[minIndex] * length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/29 13:15
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode462 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
Solution solution = new Solution();
|
||||
int[] nums = {1,2,3};
|
||||
int i = solution.minMoves2(nums);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* +1 或 -1
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int minMoves2(int[] nums) {
|
||||
// 排序后找到中位数
|
||||
Arrays.sort(nums);
|
||||
// 前缀和
|
||||
int length = nums.length;
|
||||
int[] preSum = new int[length + 1];
|
||||
for (int i = 1; i < preSum.length; i++) {
|
||||
preSum[i] = preSum[i - 1] + nums[i - 1];
|
||||
}
|
||||
// 中位数
|
||||
int middleIndex = length / 2;
|
||||
int middleValue = nums[middleIndex];
|
||||
|
||||
int left = middleIndex * middleValue - preSum[middleIndex];
|
||||
int right = preSum[preSum.length - 1] - preSum[middleIndex] - (length - middleIndex) * middleValue;
|
||||
return left + right;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/15 12:00
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode48 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
// [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
|
||||
int[][] matrix = new int[][]{{5,1,9,11},{2,4,8,10},{13,3,6,7},{15,14,12,16}};
|
||||
Solution solution = new Solution();
|
||||
solution.rotate(matrix);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public void rotate(int[][] matrix) {
|
||||
// 1 1 1 3
|
||||
// 1 2 2 3
|
||||
// 1 3 3 3
|
||||
|
||||
// 1 1 1 4
|
||||
// 1 2 2 4
|
||||
// 1 3 3 4
|
||||
// 1 4 4 4
|
||||
|
||||
// 1 1 1 4
|
||||
// 1 4 4 4
|
||||
// 4 4 4 1
|
||||
// 4 1 1 1
|
||||
|
||||
// 1 2 2 1
|
||||
// 2 1 2 3
|
||||
// 2 3 3 2
|
||||
// 3 2 2 1
|
||||
// 2 1 1 2
|
||||
|
||||
int length = matrix.length;
|
||||
|
||||
|
||||
for (int i = 0; i < length / 2; i++) {
|
||||
for (int j = i; j < length - 1 - i; j++) {
|
||||
int tmp = matrix[i][j];
|
||||
matrix[i][j] = matrix[length - j - 1][i];
|
||||
matrix[length - j - 1][i] = matrix[length - i - 1][length - j - 1];
|
||||
matrix[length - i - 1][length - j - 1] = matrix[j][length - i - 1];
|
||||
matrix[j][length - i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// int i = 0;
|
||||
// for (int j = i; j < length - 1; j++) {
|
||||
// int tmp = matrix[i][j];
|
||||
// matrix[i][j] = matrix[length - j - 1][i];
|
||||
// matrix[length - j - 1][i] = matrix[length - i - 1][length - j - 1];
|
||||
// matrix[length - i - 1][length - j - 1] = matrix[j][length - i - 1];
|
||||
// matrix[j][length - i - 1] = tmp;
|
||||
// }
|
||||
//
|
||||
// i = 1;
|
||||
// for (int j = i; j < length - 1 - i; j++) {
|
||||
// int tmp = matrix[i][j];
|
||||
// matrix[i][j] = matrix[length - j - 1][i];
|
||||
// matrix[length - j - 1][i] = matrix[length - i - 1][length - j - 1];
|
||||
// matrix[length - i - 1][length - j - 1] = matrix[j][length - i - 1];
|
||||
// matrix[j][length - i - 1] = tmp;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (int k = 0; k < length; k++) {
|
||||
for (int l = 0; l < length; l++) {
|
||||
System.out.print(matrix[k][l] + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
|
||||
*/
|
||||
public class LeetCode54 {
|
||||
|
||||
public List<Integer> spiralOrder(int[][] matrix) {
|
||||
int width = matrix[0].length;
|
||||
int height = matrix.length;
|
||||
List<Integer> s = new ArrayList<>(width * height);
|
||||
|
||||
if (width == 1) {
|
||||
|
||||
} else if (height == 1) {
|
||||
|
||||
}
|
||||
|
||||
int loop = Math.min(width, height) / 2;
|
||||
int start = 0;
|
||||
int i = 0, j = 0;
|
||||
while (start < loop) {
|
||||
|
||||
for (i = start; i < width - start - 1; i++) {
|
||||
s.add(matrix[start][i]);
|
||||
}
|
||||
|
||||
for (j = start; j < height - start - 1; j++) {
|
||||
s.add(matrix[j][i]);
|
||||
}
|
||||
|
||||
for (; i >= start + 1; i--) {
|
||||
s.add(matrix[j][i]);
|
||||
}
|
||||
|
||||
for (; j >= start + 1; j--) {
|
||||
s.add(matrix[j][i]);
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
if (width > height) {
|
||||
if (height == 1) {
|
||||
// 横向填充
|
||||
for (; i < width - start; i++) {
|
||||
s.add(matrix[start][i]);
|
||||
}
|
||||
}else if (height % 2 == 1) {
|
||||
// 横向填充
|
||||
for (; i < width - start-1; i++) {
|
||||
s.add(matrix[start][i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 纵向填充
|
||||
if (width == 1) {
|
||||
for (; j < height - start; j++) {
|
||||
s.add(matrix[j][i]);
|
||||
}
|
||||
} else if (width % 2 == 1 ) {
|
||||
for (; j < height - start - 1; j++) {
|
||||
s.add(matrix[j+1][i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 时间复杂度:O(mn)O(mn)O(mn),其中 mmm 和 nnn 分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。
|
||||
*
|
||||
* 空间复杂度:O(1)O(1)O(1)。除了输出数组以外,空间复杂度是常数。
|
||||
*
|
||||
* @param matrix
|
||||
* @return
|
||||
*/
|
||||
|
||||
public List<Integer> spiralOrder1(int[][] matrix) {
|
||||
int width = matrix[0].length;
|
||||
int height = matrix.length;
|
||||
List<Integer> s = new ArrayList<>(width * height);
|
||||
|
||||
if (height == 1) {
|
||||
int[] line = matrix[0];
|
||||
for (int i : line) {
|
||||
s.add(i);
|
||||
}
|
||||
return s;
|
||||
} else if (width == 1) {
|
||||
for (int[] ints : matrix) {
|
||||
s.add(ints[0]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int loop = Math.min(width, height) / 2;
|
||||
int start = 0;
|
||||
int i = 0, j = 0;
|
||||
while (start < loop) {
|
||||
|
||||
for (i = start; i < width - start - 1; i++) {
|
||||
s.add(matrix[start][i]);
|
||||
}
|
||||
|
||||
for (j = start; j < height - start - 1; j++) {
|
||||
s.add(matrix[j][i]);
|
||||
}
|
||||
|
||||
for (; i >= start + 1; i--) {
|
||||
s.add(matrix[j][i]);
|
||||
}
|
||||
|
||||
for (; j >= start + 1; j--) {
|
||||
s.add(matrix[j][i]);
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
if (width > height) {
|
||||
if (height % 2 == 1) {
|
||||
// 横向填充
|
||||
for (; i < width - start-1; i++) {
|
||||
s.add(matrix[start][i + 1]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (width % 2 == 1) {
|
||||
for (; j < height - start - 1; j++) {
|
||||
s.add(matrix[j+1][i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
@Test
|
||||
public void test() {
|
||||
spiralOrder1(new int[][]{
|
||||
{1,2},
|
||||
{1,3},
|
||||
{1,3}
|
||||
}).forEach(System.out::println);
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/18 23:37
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode57 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Solution solution = new Solution();
|
||||
int[][] insert = solution.insert(new int[][]{{1, 3}, {6, 9}}, new int[]{2, 5});
|
||||
for (int[] ints : insert) {
|
||||
System.out.println(Arrays.toString(ints));
|
||||
}
|
||||
// [[1,2],[3,5],[6,7],[8,10],[12,16]]
|
||||
int[][] insert1 = solution.insert(new int[][]{{1, 2}, {3, 5}, {6, 7}, {8, 10}, {12, 16}}, new int[]{4, 8});
|
||||
for (int[] ints : insert1) {
|
||||
System.out.println(Arrays.toString(ints));
|
||||
}
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* | | | |
|
||||
| |
|
||||
*
|
||||
* | | | |
|
||||
* | |
|
||||
*
|
||||
* | | | |
|
||||
* | |
|
||||
*
|
||||
* | | | |
|
||||
* | |
|
||||
*
|
||||
*
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* @param intervals
|
||||
* @param newInterval
|
||||
* @return
|
||||
*/
|
||||
public int[][] insert(int[][] intervals, int[] newInterval) {
|
||||
|
||||
List<int[]> list = new ArrayList<>(Arrays.asList(intervals));
|
||||
list.add(newInterval);
|
||||
list.sort(new Comparator<int[]>() {
|
||||
@Override
|
||||
public int compare(int[] o1, int[] o2) {
|
||||
return o1[0] - o2[0];
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 1; i < list.size(); i++) {
|
||||
int[] now = list.get(i);
|
||||
int[] before = list.get(i - 1);
|
||||
if (now[0] <= before[1]) {
|
||||
before[1] = Math.max(before[1], now[1]);
|
||||
list.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return list.toArray(new int[list.size()][2]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
|
||||
*
|
||||
*
|
||||
*
|
||||
* 示例 1:
|
||||
*
|
||||
*
|
||||
* 输入:n = 3
|
||||
* 输出:[[1,2,3],[8,9,4],[7,6,5]]
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:n = 1
|
||||
* 输出:[[1]]
|
||||
*
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 1 <= n <= 20
|
||||
*/
|
||||
public class LeetCode59 {
|
||||
|
||||
public int[][] generateMatrix(int n) {
|
||||
int cycle = 0; // 循环次数
|
||||
int start = 0; // 本次循环的开始
|
||||
int[][] ints = new int[n][n];
|
||||
int fillNumber = 1;
|
||||
int i, j;
|
||||
while (cycle++ < n / 2) {
|
||||
// 每个边填充数字
|
||||
int path = n - cycle;
|
||||
for (i = start; i < path; i++) {
|
||||
ints[start][i]=fillNumber++;
|
||||
}
|
||||
for (j = start; j < path; j++) {
|
||||
ints[j][i] = fillNumber++;
|
||||
}
|
||||
for (; i >= n - path; i--) {
|
||||
ints[j][i] = fillNumber++;
|
||||
}
|
||||
for (; j >= n - path; j--) {
|
||||
ints[j][i]=fillNumber++;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
if (n % 2 == 1) {
|
||||
ints[start][start] = fillNumber++;
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] ints = generateMatrix(11);
|
||||
for (int[] anInt : ints) {
|
||||
for (int i : anInt) {
|
||||
System.out.print(i+" ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/* [[1,2,3,4,5,6,7],
|
||||
[24,25,26,27,28,29,8],
|
||||
[23,40,41,42,43,30,9],
|
||||
[22,39,48,49,44,31,10],
|
||||
[21,38,47,46,45,32,11],
|
||||
[20,37,36,35,34,33,12],
|
||||
[19,18,17,16,15,14,13]]*/
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 69. x 的平方根
|
||||
* 简单
|
||||
* 相关标签
|
||||
* 相关企业
|
||||
* 提示
|
||||
* 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
|
||||
*
|
||||
* 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
|
||||
*
|
||||
* 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
|
||||
*
|
||||
*
|
||||
*
|
||||
* 示例 1:
|
||||
*
|
||||
* 输入:x = 4
|
||||
* 输出:2
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:x = 8
|
||||
* 输出:2
|
||||
* 解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
|
||||
*
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 0 <= x <= 231 - 1
|
||||
*/
|
||||
public class LeetCode69 {
|
||||
|
||||
|
||||
/**
|
||||
* 二分法
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public int mySqrt(int x) {
|
||||
int left = 0;
|
||||
int right = x;
|
||||
int ans = 0;
|
||||
while (left <= right) {
|
||||
int middle = (left + right) / 2;
|
||||
// 防止过长
|
||||
if ((long) middle * middle <= x) {
|
||||
// 真正的x只会小于等于x
|
||||
ans = middle;
|
||||
left = middle + 1;
|
||||
} else {
|
||||
right = middle - 1;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数学法
|
||||
* x^(1/2) = e^((lnx)/2)
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public int mySqrt1(int x) {
|
||||
if (x == 0) {
|
||||
return 0;
|
||||
}
|
||||
// 获取到的是>=正确的开方根
|
||||
double log = Math.log(x);
|
||||
int ans = (int) Math.exp(0.5 * log);
|
||||
if ((long) (ans + 1) * (ans + 1) <= x) {
|
||||
return ans + 1;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch1() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
mySqrt1(i);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/22 15:14
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode703 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
KthLargest kthLargest = new KthLargest(3, new int[]{});
|
||||
System.out.println(kthLargest.add(3));
|
||||
System.out.println(kthLargest.add(5));
|
||||
System.out.println(kthLargest.add(10));
|
||||
System.out.println(kthLargest.add(9));
|
||||
System.out.println(kthLargest.add(4));
|
||||
}
|
||||
|
||||
class KthLargest {
|
||||
|
||||
PriorityQueue<Integer> priorityQueue = null;
|
||||
int size = 0;
|
||||
|
||||
// 小顶堆 第k
|
||||
public KthLargest(int k, int[] nums) {
|
||||
priorityQueue = new PriorityQueue<>();
|
||||
this.size = k;
|
||||
for (int num : nums) {
|
||||
priorityQueue.offer(num);
|
||||
if (priorityQueue.size() > k) {
|
||||
priorityQueue.poll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int add(int val) {
|
||||
priorityQueue.offer(val);
|
||||
if (priorityQueue.size() > size) {
|
||||
priorityQueue.poll();
|
||||
}
|
||||
return priorityQueue.peek();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* 二分查找
|
||||
*
|
||||
*
|
||||
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
|
||||
示例 1:
|
||||
|
||||
输入: nums = [-1,0,3,5,9,12], target = 9
|
||||
输出: 4
|
||||
解释: 9 出现在 nums 中并且下标为 4
|
||||
示例 2:
|
||||
|
||||
输入: nums = [-1,0,3,5,9,12], target = 2
|
||||
输出: -1
|
||||
解释: 2 不存在 nums 中因此返回 -1
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
你可以假设 nums 中的所有元素是不重复的。
|
||||
n 将在 [1, 10000]之间。
|
||||
nums 的每个元素都将在 [-9999, 9999]之间。
|
||||
|
||||
|
||||
相关题目推荐
|
||||
35.搜索插入位置(opens new window)
|
||||
34.在排序数组中查找元素的第一个和最后一个位置(opens new window)
|
||||
69.x 的平方根(opens new window)
|
||||
367.有效的完全平方数(opens new window)
|
||||
#其他语言版本
|
||||
|
||||
*/
|
||||
public class LeetCode704 {
|
||||
|
||||
|
||||
/**
|
||||
* 二分查找 [left,right]
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static int search(int[] nums, int target) {
|
||||
if (nums.length == 0) {
|
||||
return -1;
|
||||
}
|
||||
// 初始化指针
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
int index = 0;
|
||||
while (left < right) {
|
||||
// 计算中间索引
|
||||
index = (right + left) / 2;
|
||||
if (nums[index] >= target) {
|
||||
right = index;
|
||||
} else{
|
||||
left = index + 1;
|
||||
}
|
||||
}
|
||||
if (nums[(right + left) / 2] == target) {
|
||||
return (right + left) / 2;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
public int search1(int[] nums, int target) {
|
||||
int left = 0; // 左指针,初始指向数组最左边的位置
|
||||
int right = nums.length - 1; // 右指针,初始指向数组最右边的位置
|
||||
while (left <= right) { // 当左指针小于等于右指针时,循环执行
|
||||
int mid = left + (right - left) / 2; // 中间指针,计算左指针和右指针的中间位置
|
||||
if (nums[mid] == target) { // 如果中间位置的数值等于目标数值
|
||||
return mid; // 返回中间位置的索引
|
||||
} else if (nums[mid] < target) { // 如果中间位置的数值小于目标数值
|
||||
left = mid + 1; // 将左指针移动到中间位置的右边
|
||||
} else { // 如果中间位置的数值大于目标数值
|
||||
right = mid - 1; // 将右指针移动到中间位置的左边
|
||||
}
|
||||
}
|
||||
return -1; // 没有找到目标数值,返回-1
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 二分查找 [left,right)
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int search2(int[] nums, int target) {
|
||||
int left = 0;
|
||||
int right = nums.length;
|
||||
while (left < right) {
|
||||
int middle = (left + right) / 2;
|
||||
if (nums[left] == target) {
|
||||
return left;
|
||||
} else if (nums[middle] >= target) {
|
||||
right = middle;
|
||||
} else {
|
||||
left = middle+1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearch1() {
|
||||
LeetCode704 solution = new LeetCode704();
|
||||
|
||||
int[] nums = {1};
|
||||
int target = 5;
|
||||
Assert.assertEquals(-1, solution.search2(nums, target));
|
||||
|
||||
nums = new int[]{10, 20, 30, 40};
|
||||
target = 30;
|
||||
Assert.assertEquals(2, solution.search1(nums, target));
|
||||
|
||||
nums = new int[]{1, 2, 3};
|
||||
target = 4;
|
||||
Assert.assertEquals(-1, solution.search1(nums, target));
|
||||
|
||||
|
||||
nums = new int[]{1};
|
||||
target = 1;
|
||||
Assert.assertEquals(0, solution.search1(nums, target));
|
||||
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/23 16:13
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode713 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1,2,3};
|
||||
int k = 0;
|
||||
int res = new Solution1().numSubarrayProductLessThanK(nums, k);
|
||||
System.out.println(res);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int numSubarrayProductLessThanK(int[] nums, int k) {
|
||||
|
||||
|
||||
int res = 0;
|
||||
int pro = 1;
|
||||
for (int left = 0, right = 0; right < nums.length; right++) {
|
||||
pro *= nums[right];
|
||||
while (pro >= k) {
|
||||
// 一旦 找到比k小的,左边就往前,并且pro得到最新的
|
||||
pro /= nums[left++];
|
||||
}
|
||||
res += right - left + 1;
|
||||
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public int numSubarrayProductLessThanK(int[] nums, int k) {
|
||||
if (k <= 1) return 0; //1 <= nums[i] <= 1000
|
||||
int res = 0;
|
||||
int pro = 1;
|
||||
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
while (right < nums.length) {
|
||||
pro *= nums[right];
|
||||
// 直到总乘积大于k,左边才左移
|
||||
while (pro >= k) {
|
||||
pro /= nums[left];
|
||||
left++;
|
||||
}
|
||||
res += right - left + 1;
|
||||
right++;
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/23 9:18
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode73 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] matrix = new int[][]{{1, 1, 1}, {1, 0, 1}, {1, 1, 1}};
|
||||
new Solution().setZeroes(matrix);
|
||||
for (int[] ints : matrix) {
|
||||
System.out.println(Arrays.toString(ints));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
public void setZeroes(int[][] matrix) {
|
||||
|
||||
int yLen = matrix.length;
|
||||
boolean[] row = new boolean[yLen];
|
||||
int xLen = matrix[0].length;
|
||||
boolean[] col = new boolean[xLen];
|
||||
|
||||
|
||||
for (int y = 0; y < yLen; y++) {
|
||||
for (int x = 0; x < xLen; x++) {
|
||||
if (matrix[y][x] == 0) {
|
||||
row[y] = true;
|
||||
col[x] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < yLen; y++) {
|
||||
for (int x = 0; x < xLen; x++) {
|
||||
if (row[y] || col[x]) {
|
||||
matrix[y][x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/16 16:23
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode80 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = new int[]{0, 0, 1, 1, 1, 1, 2, 3, 3};
|
||||
System.out.println(new Solution().removeDuplicates(nums));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 双指针
|
||||
* - 跳跃判断,如果不一样就让left向前,并赋值
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int removeDuplicates(int[] nums) {
|
||||
if (nums.length < 3) return nums.length;
|
||||
int leftSlow = 0;
|
||||
int rightFast = 2;
|
||||
while (rightFast < nums.length) {
|
||||
if (nums[rightFast] != nums[leftSlow]) {
|
||||
nums[leftSlow + 2] = nums[rightFast];
|
||||
leftSlow++;
|
||||
}
|
||||
rightFast++;
|
||||
}
|
||||
return leftSlow + 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int removeDuplicates(int[] nums) {
|
||||
// 数组中的一号和二号元素肯定不用删除
|
||||
int index = 2;
|
||||
for(int i = 2 ; i < nums.length ; i++) {
|
||||
if(nums[i] != nums[index-2]) {
|
||||
nums[index++] = nums[i];
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import cn.whaifree.leetCode.model.ListNode;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/6 12:45
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode86 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ListNode listNode = ListNode.listNodeFromArray(new int[]{1, 4, 3, 2, 5, 2});
|
||||
ListNode listNode1 = new Solution().partition(listNode, 3);
|
||||
listNode1.printList();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
class Solution {
|
||||
public ListNode partition(ListNode head, int x) {
|
||||
ListNode pre = new ListNode(-1, head);
|
||||
ListNode small = new ListNode(-1);
|
||||
ListNode big = new ListNode(-1);
|
||||
ListNode smallIndex = small;
|
||||
ListNode bigIndex = big;
|
||||
ListNode index = head;
|
||||
while (index != null) {
|
||||
if (index.val < x) {
|
||||
smallIndex.next = index;
|
||||
smallIndex = smallIndex.next;
|
||||
} else {
|
||||
bigIndex.next = index;
|
||||
bigIndex = bigIndex.next;
|
||||
}
|
||||
index = index.next;
|
||||
}
|
||||
smallIndex.next = big.next;
|
||||
bigIndex.next = null;
|
||||
return small.next;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/16 16:11
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode88 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums1 = new int[]{1,2,3,0,0,0};
|
||||
int[] nums2 = new int[]{2,5,6};
|
||||
new Solution().merge(nums1, 3, nums2, 3);
|
||||
System.out.println(Arrays.toString(nums1));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public void merge(int[] nums1, int m, int[] nums2, int n) {
|
||||
int index = 0;
|
||||
int[] res = new int[nums1.length];
|
||||
int index1 = 0;
|
||||
int index2 = 0;
|
||||
while (index1 < m && index2 < n) {
|
||||
if (nums1[index1] < nums2[index2]) {
|
||||
res[index++] = nums1[index1++];
|
||||
}else {
|
||||
res[index++] = nums2[index2++];
|
||||
}
|
||||
}
|
||||
|
||||
while (index1 < m) {
|
||||
res[index++] = nums1[index1++];
|
||||
}
|
||||
while (index2 < n) {
|
||||
res[index++] = nums2[index2++];
|
||||
}
|
||||
|
||||
System.arraycopy(res, 0, nums1, 0, index);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
*
|
||||
* 排序算法有这几种:
|
||||
* 常见的排序算法包括但不限于以下这些:
|
||||
* 冒泡排序:从第一个元素开始与右侧元素两两比较并交换,直到右侧成为有序部分。
|
||||
* 选择排序:有序部分在左侧,在剩余元素中找到最小的那个元素,并与剩余元素中第一个元素交换。
|
||||
* 插入排序:有序部分在左侧,将剩余元素中第一个元素不断向左交换,直到此元素处于有序部分恰当位置。
|
||||
* 希尔排序:取一个间隔值,距离为间隔值的元素为一组,将整个数组分为若干组。每组内进行插入排序。缩小间隔值并重复,直到间隔值为1,即所有元素在同一组。
|
||||
*
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/20 14:20
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode912_SortArrays {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
int[] nums = {5,1,1,2,0,0};
|
||||
|
||||
// int[] res = new Solution2().sortArray(nums);
|
||||
// System.out.println(Arrays.toString(res));
|
||||
//
|
||||
// int[] ints = Arrays.copyOf(res, res.length);
|
||||
// Arrays.sort(nums);
|
||||
// System.out.println(Arrays.equals(ints, nums));
|
||||
|
||||
int[] res2 = new MergeSort.Solution().sortArray(nums);
|
||||
|
||||
System.out.println(Arrays.toString(res2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 冒泡
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int[] sortArray(int[] nums) {
|
||||
boolean isSwap = false;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
for (int j = 1; j < nums.length - i; j++) {
|
||||
if (nums[j] < nums[j - 1]) {
|
||||
isSwap = true;
|
||||
int tmp = nums[j];
|
||||
nums[j] = nums[j - 1];
|
||||
nums[j - 1] = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
if (!isSwap) {
|
||||
return nums;
|
||||
}
|
||||
isSwap = false;
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* 选择排序
|
||||
* 选择右边区间的最小值与左边替换
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int[] sortArray(int[] nums) {
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
int minIndex = i;
|
||||
for (int j = i+1; j < nums.length; j++) {
|
||||
if (nums[minIndex] > nums[j]) {
|
||||
minIndex = j;
|
||||
}
|
||||
}
|
||||
// 交换min与i
|
||||
int tmp = nums[i];
|
||||
nums[i] = nums[minIndex];
|
||||
nums[minIndex] = tmp;
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution2 {
|
||||
/**
|
||||
* 插入排序 j不断往前插入替换到合适位置
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int[] sortArray(int[] nums) {
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
int j = i;
|
||||
while (j > 0 && nums[j] < nums[j - 1]) {
|
||||
// 交换j和j-1
|
||||
int tmp = nums[j];
|
||||
nums[j] = nums[j - 1];
|
||||
nums[j - 1] = tmp;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
}
|
||||
|
||||
class SolutionQuickSort {
|
||||
/**
|
||||
* 插入排序 j不断往前插入替换到合适位置
|
||||
*
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int[] sortArray(int[] nums) {
|
||||
|
||||
|
||||
return nums;
|
||||
}
|
||||
|
||||
public void part(int[] nums, int start, int end) {
|
||||
if (start > end) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class MergeSort{
|
||||
static class Solution {
|
||||
|
||||
// 归并排序
|
||||
public int[] sortArray(int[] nums) {
|
||||
if (nums.length <= 1) {
|
||||
return nums;
|
||||
}
|
||||
int mid = nums.length / 2;
|
||||
int[] left = Arrays.copyOfRange(nums, 0, mid);
|
||||
int[] right = Arrays.copyOfRange(nums, mid, nums.length);
|
||||
left = sortArray(left);
|
||||
right = sortArray(right);
|
||||
return merge(left, right);
|
||||
}
|
||||
|
||||
public int[] merge(int[] left, int[] right) {
|
||||
int[] res = new int[left.length + right.length];
|
||||
int leftIndex = 0;
|
||||
int rightIndex = 0;
|
||||
int index = 0;
|
||||
while (leftIndex < left.length && rightIndex < right.length) {
|
||||
if (left[leftIndex] < right[rightIndex]) {
|
||||
res[index] = left[leftIndex];
|
||||
leftIndex++;
|
||||
}else {
|
||||
res[index] = right[rightIndex];
|
||||
rightIndex++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
while (leftIndex < left.length) {
|
||||
res[index] = left[leftIndex];
|
||||
leftIndex++;
|
||||
index++;
|
||||
}
|
||||
while (rightIndex < right.length) {
|
||||
res[index] = right[rightIndex];
|
||||
rightIndex++;
|
||||
index++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class QuickSort{
|
||||
|
||||
/**
|
||||
* 快速排序
|
||||
*/
|
||||
static class Solution4 {
|
||||
public int[] sortArray(int[] nums) {
|
||||
|
||||
quickSort(nums, 0, nums.length-1);
|
||||
return nums;
|
||||
}
|
||||
|
||||
public int[] quickSort(int[] nums, int left,int right){
|
||||
//如果左指针大于右指针,怎退出循环
|
||||
if(left > right){
|
||||
return null;
|
||||
}
|
||||
|
||||
//! 随机挑选一个幸运儿
|
||||
int q = new Random().nextInt(right - left + 1) + left;
|
||||
swap(nums, right, q);
|
||||
|
||||
int base = nums[left];
|
||||
int i = left;
|
||||
int j = right;
|
||||
while(i != j){
|
||||
//从右往左遍历,当右指针指向的元素大于等于基数时,j--。右指针持续向左移动
|
||||
while(nums[j]>=base && i < j){
|
||||
j--;
|
||||
}
|
||||
//从左往右遍历,当左指针指向的元素小于等于基数时,i++。左指针持续向右移动
|
||||
while(nums[i]<=base && i < j){
|
||||
i++;
|
||||
}
|
||||
//当左右两个指针停下来时,交换两个元素
|
||||
swap(nums, i, j);
|
||||
|
||||
}
|
||||
swap(nums,i,left);
|
||||
quickSort(nums,left, i-1);
|
||||
quickSort(nums,i+1,right);
|
||||
return nums;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void swap(int[] nums, int index1, int indexB) {
|
||||
int tmp = nums[index1];
|
||||
nums[index1] = nums[indexB];
|
||||
nums[indexB] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// class Solution11 {
|
||||
// public int[] sortArray(int[] nums) {
|
||||
// quick_sort(nums, 0, nums.length - 1);
|
||||
// return nums;
|
||||
// }
|
||||
//
|
||||
// private void quick_sort(int[] nums, int left, int right) {
|
||||
// if (left >= right) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// int i = left;
|
||||
// int j = right;
|
||||
// //! 随机挑选一个幸运儿
|
||||
// int q = new Random().nextInt(right - left + 1) + left;
|
||||
// swap(nums, right, q);
|
||||
//
|
||||
// while (i < j) {
|
||||
// while (nums[i] <= nums[right] && i < j) {
|
||||
// i++;
|
||||
// }
|
||||
// while (nums[right] >= nums[left] && i < j) {
|
||||
// j--;
|
||||
// }
|
||||
// swap(nums, i, j);
|
||||
// }
|
||||
//
|
||||
// swap(nums, i, right);
|
||||
//
|
||||
//
|
||||
// quick_sort(nums, left, i - 1);
|
||||
// quick_sort(nums, i + 1, right);
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// private void swap(int[] nums, int i, int j) {
|
||||
// int temp = nums[i];
|
||||
// nums[i] = nums[j];
|
||||
// nums[j] = temp;
|
||||
// }
|
||||
// }
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 977. 有序数组的平方
|
||||
*
|
||||
* 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
|
||||
*
|
||||
* 示例 1:
|
||||
*
|
||||
* 输入:nums = [-4,-1,0,3,10]
|
||||
* 输出:[0,1,9,16,100]
|
||||
* 解释:平方后,数组变为 [16,1,0,9,100]
|
||||
* 排序后,数组变为 [0,1,9,16,100]
|
||||
*
|
||||
* 示例 2:
|
||||
*
|
||||
* 输入:nums = [-7,-3,2,3,11]
|
||||
* 输出:[4,9,9,49,121]
|
||||
*
|
||||
* 提示:
|
||||
*
|
||||
* 1 <= nums.length <= 104
|
||||
* -104 <= nums[i] <= 104
|
||||
* nums 已按 非递减顺序 排序
|
||||
*
|
||||
*
|
||||
* 进阶:
|
||||
*
|
||||
* 请你设计时间复杂度为 O(n) 的算法解决本问题
|
||||
*
|
||||
* 更多挑战
|
||||
* 88. 合并两个有序数组
|
||||
* 360. 有序转化数组
|
||||
*/
|
||||
public class LeetCode977 {
|
||||
|
||||
/**
|
||||
* 找到第一个左边小于0,右边大于等于0的点
|
||||
* 左右两个指针
|
||||
* 平方后必然是,【递减 0 递增】
|
||||
* [-3,-1,0,2,5]
|
||||
* [9,1,0,4,25]
|
||||
*
|
||||
* 让左边的循环插入到右边合适的位置
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int[] sortedSquares(int[] nums) {
|
||||
|
||||
int middle = nums.length;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (nums[i] >= 0) {
|
||||
middle = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 此时就有两个数组了
|
||||
// [0,middle-1] 为递减的
|
||||
// [middle, length-1] 为递增的
|
||||
int[] ints = new int[nums.length];
|
||||
int leftIndex = middle -1;
|
||||
int rightIndex = middle;
|
||||
int intIndex = 0;
|
||||
while (leftIndex >= 0 && rightIndex < nums.length) {
|
||||
if (nums[leftIndex] * nums[leftIndex] < nums[rightIndex] * nums[rightIndex]) {
|
||||
ints[intIndex++] = nums[leftIndex] * nums[leftIndex];
|
||||
leftIndex--;
|
||||
} else {
|
||||
ints[intIndex++] = nums[rightIndex] * nums[rightIndex];
|
||||
rightIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
while (leftIndex >= 0) {
|
||||
ints[intIndex++] = nums[leftIndex] * nums[leftIndex];
|
||||
leftIndex--;
|
||||
}
|
||||
while (rightIndex <= nums.length-1) {
|
||||
ints[intIndex++] = nums[rightIndex] * nums[rightIndex];
|
||||
rightIndex++;
|
||||
}
|
||||
|
||||
return ints;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 不考虑0的双指针
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int[] sortedSquares1(int[] nums) {
|
||||
int[] ints = new int[nums.length];
|
||||
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
int index = 0;
|
||||
while (left <= right) {
|
||||
if (nums[left] * nums[left] < nums[right] * nums[right]) {
|
||||
ints[index++] = nums[right] * nums[right];
|
||||
right--;
|
||||
} else {
|
||||
ints[index++] = nums[left] * nums[left];
|
||||
left++;
|
||||
}
|
||||
}
|
||||
|
||||
// 逆序
|
||||
int value = 0;
|
||||
for (int i = 0; i < ints.length / 2; i++) {
|
||||
value = ints[i];
|
||||
ints[i] = ints[ints.length - i - 1];
|
||||
ints[ints.length - 1 - i] = value;
|
||||
}
|
||||
|
||||
return ints;
|
||||
}
|
||||
|
||||
public int[] sortedSquares2(int[] nums) {
|
||||
int[] ints = new int[nums.length];
|
||||
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
// 存入新数组的索引,从大往小存
|
||||
int index = nums.length - 1;
|
||||
while (left <= right) {
|
||||
// 负数 + 正数 > 0 则 |负数| < |正数|
|
||||
if (nums[left] + nums[right] > 0) {
|
||||
ints[index--] = nums[right] * nums[right];
|
||||
right--;
|
||||
} else {
|
||||
ints[index--] = nums[left] * nums[left];
|
||||
left++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ints;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] ints = sortedSquares2(new int[]{-3,-1,4,10});
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
System.out.println(ints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package cn.whaifree.leetCode.Array;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/20 12:41
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode989 {
|
||||
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
|
||||
// 创建一个RandomAccessFile对象,用于读取指定路径下的文件
|
||||
RandomAccessFile reader = new RandomAccessFile("D:\\Downloads\\a8d88f60-603e-405f-b67b-6774dd14a507.jpg", "r");
|
||||
// 获取文件通道
|
||||
FileChannel channel = reader.getChannel();
|
||||
// 分配读取指定文件大小的缓冲区
|
||||
ByteBuffer buffer = ByteBuffer.allocate((int) reader.length());
|
||||
// 从文件通道中读取数据到缓冲区
|
||||
channel.read(buffer);
|
||||
|
||||
|
||||
// 创建一个RandomAccessFile对象,用于将缓冲区的数据写入到新的文件
|
||||
RandomAccessFile writer = new RandomAccessFile("D:\\Downloads\\new_file.jpg", "rw");
|
||||
// 获取文件通道
|
||||
FileChannel newChannel = writer.getChannel();
|
||||
// 将缓冲区的数据写入到新的文件
|
||||
newChannel.write(buffer);
|
||||
// 关闭文件通道
|
||||
channel.close();
|
||||
newChannel.close();
|
||||
|
||||
byte[] array = ByteBuffer.allocate(8).putDouble(1.0).array();
|
||||
System.out.println(Arrays.toString(array));
|
||||
|
||||
int[] num = {9,9,9,9,9,9,9,9,9,9};
|
||||
int k = 1;
|
||||
Solution solution = new Solution();
|
||||
List<Integer> res = solution.addToArrayForm(num, k);
|
||||
System.out.println(res);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public List<Integer> addToArrayForm(int[] num, int k) {
|
||||
int indexA = num.length - 1;
|
||||
int m = k;
|
||||
boolean flag = false;
|
||||
LinkedList<Integer> res = new LinkedList<>();
|
||||
while (indexA >= 0 && m > 0) {
|
||||
int sum = num[indexA] + m % 10;
|
||||
sum = flag ? sum + 1 : sum;
|
||||
flag = sum >= 10;
|
||||
|
||||
res.addFirst(sum % 10);
|
||||
|
||||
indexA--;
|
||||
m /= 10;
|
||||
}
|
||||
|
||||
if (indexA < 0 && m <= 0 && flag) {
|
||||
res.addFirst(1);
|
||||
return res;
|
||||
}
|
||||
|
||||
while (indexA >= 0) {
|
||||
int sum = num[indexA];
|
||||
sum = flag ? sum + 1 : sum;
|
||||
flag = sum >= 10;
|
||||
res.addFirst(sum % 10);
|
||||
indexA--;
|
||||
}
|
||||
|
||||
while (m>0) {
|
||||
int sum = m % 10;
|
||||
sum = flag ? sum + 1 : sum;
|
||||
flag = sum >= 10;
|
||||
res.addFirst(sum % 10);
|
||||
m /= 10;
|
||||
}
|
||||
if (flag) {
|
||||
res.addFirst(1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/10 15:12
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode131 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String abbc = "aaab";
|
||||
new Solution().partition(abbc).forEach(
|
||||
list -> {
|
||||
System.out.println(list);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<String>> res = new ArrayList<>();
|
||||
List<String> path = new ArrayList<>();
|
||||
public List<List<String>> partition(String s) {
|
||||
backTracking(s, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. 判断回文字符串函数 <br>
|
||||
* 2. 从start开始切割,到i i++<br>
|
||||
* 递归
|
||||
* <img src="https://code-thinking.cdn.bcebos.com/pics/131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.jpg">
|
||||
*
|
||||
* @param s
|
||||
* @param start
|
||||
*/
|
||||
public void backTracking(String s, int start) {
|
||||
if (start >= s.length()) {
|
||||
res.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
for (int i = start; i < s.length(); i++) {
|
||||
if (isPalindrome(s, start, i)) {
|
||||
String substring = s.substring(start, i + 1);
|
||||
path.add(substring);
|
||||
backTracking(s, i + 1);
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//判断是否是回文串
|
||||
private boolean isPalindrome(String s, int startIndex, int end) {
|
||||
for (int i = startIndex, j = end; i < j; i++, j--) {
|
||||
if (s.charAt(i) != s.charAt(j)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/2 10:31
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode17 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String digits = "23";
|
||||
new Solution().letterCombinations(digits).forEach(s -> System.out.println(s));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
List<String> map = new ArrayList<>();
|
||||
List<String> result = new ArrayList<>();
|
||||
// 记录 路径
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
public List<String> letterCombinations(String digits) {
|
||||
if (digits.length() == 0) {
|
||||
return result;
|
||||
}
|
||||
map.add(0, null);
|
||||
map.add(1, null);
|
||||
map.add(2, "abc");
|
||||
map.add(3, "def");
|
||||
map.add(4, "ghi");
|
||||
map.add(5, "jkl");
|
||||
map.add(6, "mno");
|
||||
map.add(7, "pqrs");
|
||||
map.add(8, "tuv");
|
||||
map.add(9, "wxyz");
|
||||
backTracking(digits, 0, digits.length());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param digits 原始字符 23
|
||||
* @param number 使用到第几个字符
|
||||
* @param needLength 需要几个字符,等价于digits.length
|
||||
*/
|
||||
void backTracking(String digits, int number,int needLength) {
|
||||
if (s.length() == needLength) {
|
||||
result.add(new String(s.toString()));
|
||||
return;
|
||||
}
|
||||
|
||||
int c = digits.charAt(number) - 48;
|
||||
String sValue = map.get(c);
|
||||
int length = sValue.length();
|
||||
// 对每个字符处理
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c1 = sValue.charAt(i);
|
||||
s.append(c1);
|
||||
backTracking(digits, number + 1, needLength);
|
||||
s.deleteCharAt(s.length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
List<String> map = new ArrayList<>();
|
||||
List<String> result = new ArrayList<>();
|
||||
// 记录 路径
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
public List<String> letterCombinations(String digits) {
|
||||
if (digits.length() == 0) {
|
||||
return result;
|
||||
}
|
||||
map.add(0, null);
|
||||
map.add(1, null);
|
||||
map.add(2, "abc");
|
||||
map.add(3, "def");
|
||||
map.add(4, "ghi");
|
||||
map.add(5, "jkl");
|
||||
map.add(6, "mno");
|
||||
map.add(7, "pqrs");
|
||||
map.add(8, "tuv");
|
||||
map.add(9, "wxyz");
|
||||
|
||||
backTracking(digits, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param digits 原始字符 23
|
||||
* @param number 使用到第几个字符
|
||||
*/
|
||||
void backTracking(String digits, int number) {
|
||||
if (s.length() == digits.length()) {
|
||||
result.add(new String(s.toString()));
|
||||
return;
|
||||
}
|
||||
|
||||
int c = digits.charAt(number) - 48;
|
||||
String sValue = map.get(c);
|
||||
int length = sValue.length();
|
||||
// 对每个字符处理
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c1 = sValue.charAt(i);
|
||||
s.append(c1);
|
||||
backTracking(digits, number + 1);
|
||||
s.deleteCharAt(s.length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/2 8:22
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode216 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Solution solution = new Solution();
|
||||
solution.combinationSum3(9, 45).forEach(
|
||||
list -> {
|
||||
System.out.println(list);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new LinkedList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
int sum = 0;
|
||||
/**
|
||||
* 相加之和为n的k个数的组合
|
||||
* @param k
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> combinationSum3(int k, int n) {
|
||||
circle(1, 9, n, k);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void circle(int start, int end, int n, int k) {
|
||||
if (path.size() == k && sum == n) {
|
||||
res.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 如果sum>n了,证明往后加只会更大,因为都是正数,就不再继续了
|
||||
// sum>n
|
||||
//
|
||||
// 2. 如果 9个数要9个数
|
||||
// 已经选择size
|
||||
// 还需选择k-size
|
||||
// 可以选择的数end-start
|
||||
// 可以选择的数<还需选择的数 end-start<k-size
|
||||
|
||||
for (int i = start; i <= end ; i++) {
|
||||
// 可以选择的数<还需选择的数
|
||||
if (end - i + 1 < k - path.size()) {
|
||||
return;
|
||||
}
|
||||
path.add(i);
|
||||
sum += i;
|
||||
|
||||
// 如果 加上某个数已经超过了n,那么剩下的正数都没必要再加了。如1234,后面只能选5678,如果去了4加了5678必然会超过n
|
||||
if (sum > n) {
|
||||
path.remove(path.size() - 1);
|
||||
sum -= i;
|
||||
return;
|
||||
}
|
||||
circle(i + 1, end, n, k);
|
||||
path.remove(path.size() - 1);
|
||||
sum -= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/20 10:29
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode332difficult {
|
||||
@Test
|
||||
public void test() {
|
||||
List<List<String>> tickets = new ArrayList<>();
|
||||
// 加上这一串 [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
|
||||
// tickets.add(new ArrayList<String>() {{
|
||||
// add("JFK");
|
||||
// add("SFO");
|
||||
// }});
|
||||
// tickets.add(new ArrayList<String>() {{
|
||||
// add("JFK");
|
||||
// add("ATL");
|
||||
// }});
|
||||
// tickets.add(new ArrayList<String>() {{
|
||||
// add("SFO");
|
||||
// add("ATL");
|
||||
// }});
|
||||
// tickets.add(new ArrayList<String>() {{
|
||||
// add("ATL");
|
||||
// add("JFK");
|
||||
// }});
|
||||
// tickets.add(new ArrayList<String>() {{
|
||||
// add("ATL");
|
||||
// add("SFO");
|
||||
// }});
|
||||
|
||||
String[][] routes = {
|
||||
{"JFK", "SFO"},
|
||||
{"JFK", "ATL"},
|
||||
{"SFO", "JFK"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"},
|
||||
{"ATL", "AAA"},
|
||||
{"AAA", "BBB"},
|
||||
{"BBB", "ATL"}
|
||||
};
|
||||
|
||||
|
||||
for (String[] route : routes) {
|
||||
tickets.add(Arrays.asList(route));
|
||||
}
|
||||
|
||||
Solution1 solution = new Solution1();
|
||||
solution.findItinerary(tickets).forEach(
|
||||
list -> {
|
||||
System.out.println(list);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 超时
|
||||
*/
|
||||
class Solution {
|
||||
|
||||
List<String> res = new ArrayList<>();
|
||||
private LinkedList<String> path = new LinkedList<>();
|
||||
boolean[] used = null;
|
||||
public List<String> findItinerary(List<List<String>> tickets) {
|
||||
Collections.sort(tickets, new Comparator<List<String>>() {
|
||||
@Override
|
||||
public int compare(List<String> a, List<String> b) {
|
||||
// 两个字符串比较
|
||||
return a.get(1).compareTo(a.get(1));
|
||||
}
|
||||
});
|
||||
// 最后,会按照目的地进行排序["JFK","SFO"],["JFK","ATL"],会变成["JFK","ATL"],["JFK","SFO"]
|
||||
|
||||
path.add("JFK");
|
||||
used = new boolean[tickets.size()];
|
||||
|
||||
// 1. 字典排序选择
|
||||
// 2. 已经走过的标记
|
||||
backTracking(tickets);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(List<List<String>> tickets) {
|
||||
if (path.size() == 1 + tickets.size()) {
|
||||
res = new LinkedList(path);
|
||||
return;
|
||||
}
|
||||
|
||||
int size = tickets.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (!used[i] && path.getLast().equals(tickets.get(i).get(0))) {
|
||||
String target = tickets.get(i).get(1);
|
||||
path.add(target);
|
||||
used[i] = true;
|
||||
|
||||
backTracking(tickets);
|
||||
|
||||
used[i] = false;
|
||||
path.removeLast();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 在tickets返回未被use的索引,多个索引进行比较
|
||||
// *
|
||||
// * @param tickets
|
||||
// * @return 在tickets中的索引
|
||||
// */
|
||||
// public int compareAndUnUsed(List<List<String>> tickets, String start) {
|
||||
// int res = -1;
|
||||
// for (int i = 0; i < tickets.size(); i++) {
|
||||
// List<String> aPath = tickets.get(i);
|
||||
// String st = aPath.get(0);
|
||||
// if (start.equals(st) && used[i] == false) {
|
||||
// if (res != -1) {
|
||||
// String target = aPath.get(1);
|
||||
// String beforeRes = tickets.get(res).get(1);
|
||||
// if (!compareBeforeIsBetter(beforeRes, target)) {
|
||||
// res = i;
|
||||
// }
|
||||
// }else {
|
||||
// res = i;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
//
|
||||
// public boolean compareBeforeIsBetter(String before,String after) {
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
// char be = before.charAt(i);
|
||||
// char af = after.charAt(i);
|
||||
// if (be > af) {
|
||||
// return false;
|
||||
// } else if (be < af) {
|
||||
// return true;
|
||||
// }
|
||||
// // 如果字母相同,比较下一个字母
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Solution1 {
|
||||
|
||||
List<String> res = new ArrayList<>();
|
||||
private LinkedList<String> path = new LinkedList<>();
|
||||
boolean[] used = null;
|
||||
public List<String> findItinerary(List<List<String>> tickets) {
|
||||
Collections.sort(tickets, new Comparator<List<String>>() {
|
||||
@Override
|
||||
public int compare(List<String> a, List<String> b) {
|
||||
// 两个字符串比较
|
||||
return a.get(1).compareTo(b.get(1));
|
||||
}
|
||||
});
|
||||
// 最后,会按照目的地进行排序["JFK","SFO"],["JFK","ATL"],会变成["JFK","ATL"],["JFK","SFO"]
|
||||
|
||||
path.add("JFK");
|
||||
used = new boolean[tickets.size()];
|
||||
|
||||
// 1. 字典排序选择
|
||||
// 2. 已经走过的标记
|
||||
backTracking(tickets);
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean backTracking(List<List<String>> tickets) {
|
||||
if (path.size() == 1 + tickets.size()) {
|
||||
res = new LinkedList(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tickets.size(); i++) {
|
||||
if (!used[i] && path.getLast().equals(tickets.get(i).get(0))) {
|
||||
String target = tickets.get(i).get(1);
|
||||
path.add(target);
|
||||
used[i] = true;
|
||||
|
||||
if (backTracking(tickets)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
used[i] = false;
|
||||
path.removeLast();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/6 23:57
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode39 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
new Solution().combinationSum(new int[]{2, 3, 6, 7}, 7).forEach(
|
||||
list -> {
|
||||
list.forEach(System.out::print);
|
||||
System.out.println();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
public List<List<Integer>> combinationSum(int[] candidates, int target) {
|
||||
backTracking(candidates, 0, target);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] candidates, int index, int need) {
|
||||
if (need < 0) {
|
||||
return;
|
||||
}
|
||||
if (need == 0) {
|
||||
res.add(new ArrayList<>(path));
|
||||
}
|
||||
for (int i = index; i < candidates.length ; i++) {
|
||||
path.add(candidates[i]);
|
||||
backTracking(candidates, i, need - candidates[i]);
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/6 23:57
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode40 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
new Solution().combinationSum2(new int[]{10,1,2,7,6,1,5}, 8).forEach(
|
||||
list -> {
|
||||
list.forEach(System.out::print);
|
||||
System.out.println();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new LinkedList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
boolean[] used;
|
||||
|
||||
/**
|
||||
* 结果不能重复!!!!
|
||||
* 1. 排序candidates
|
||||
* 2. 使用used[]数组记录使用
|
||||
* 3. 一旦candi[index]==cnadi[index-1]&&user[index]=true,那么就是用过的,不添加
|
||||
* @param candidates
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
|
||||
Arrays.sort(candidates);
|
||||
used = new boolean[candidates.length];
|
||||
backTracking(candidates, 0, target);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] candidates, int index, int need) {
|
||||
if (need < 0) {
|
||||
return;
|
||||
}
|
||||
if (need == 0) {
|
||||
res.add(new ArrayList<>(path));
|
||||
}
|
||||
for (int i = index; i < candidates.length ; i++) {
|
||||
|
||||
// 取第一个数先 used放1,再放0;
|
||||
// 取第二个数时,如果can两个数相同,并且used为0,表示前一个数用过。
|
||||
// 如果 used为1,表示还没从递归中出来,即是【1,1】中的第二个1,是需要的
|
||||
if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
path.add(candidates[i]);
|
||||
used[i] = true;
|
||||
backTracking(candidates, i+1, need - candidates[i]);
|
||||
used[i] = false;
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/19 11:01
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode46 {
|
||||
@Test
|
||||
public void test() {
|
||||
new Solution1().permute(new int[]{1, 2, 3}).forEach(
|
||||
list -> {
|
||||
System.out.println(list);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
boolean[] used = null;
|
||||
|
||||
|
||||
public List<List<Integer>> permute(int[] nums) {
|
||||
used = new boolean[nums.length];
|
||||
backTracking(nums);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] nums) {
|
||||
|
||||
if (path.size() == nums.length) {
|
||||
res.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (used[i] == true) {
|
||||
continue;
|
||||
}
|
||||
used[i] = true;
|
||||
path.add(nums[i]);
|
||||
backTracking(nums);
|
||||
used[i] = false;
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
|
||||
|
||||
public List<List<Integer>> permute(int[] nums) {
|
||||
backTracking(nums);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] nums) {
|
||||
|
||||
if (path.size() == nums.length) {
|
||||
res.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (path.contains(nums[i])) {
|
||||
continue;
|
||||
}
|
||||
path.add(nums[i]);
|
||||
backTracking(nums);
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import cn.whaifree.leetCode.model.TreeNode;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/19 16:41
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode47 {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
new Solution1().permuteUnique(new int[]{1, 1, 2}).forEach(
|
||||
list -> {
|
||||
System.out.println(list);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用层的set+路径的bool[]
|
||||
*/
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
boolean[] used = null;
|
||||
/**
|
||||
* 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
|
||||
* 相比46题,不重复
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> permuteUnique(int[] nums) {
|
||||
used = new boolean[nums.length];
|
||||
|
||||
backTracking(nums);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] nums) {
|
||||
if (path.size() == nums.length) {
|
||||
res.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
|
||||
// 这个set用来对每层进行过滤,每层不能重复
|
||||
// used对每个路径进行过滤,没个路径不会出现同一个index,但有可能多个index都是同一个元素
|
||||
HashSet<Integer> set = new HashSet<>();
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (used[i] == true || set.contains(nums[i])) {
|
||||
continue;
|
||||
}
|
||||
set.add(nums[i]);
|
||||
used[i] = true;
|
||||
path.add(nums[i]);
|
||||
backTracking(nums);
|
||||
used[i] = false;
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用排序+used
|
||||
*/
|
||||
class Solution1 {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
boolean[] used = null;
|
||||
/**
|
||||
* 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
|
||||
* 相比46题,不重复
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> permuteUnique(int[] nums) {
|
||||
used = new boolean[nums.length];
|
||||
Arrays.sort(nums);
|
||||
|
||||
backTracking(nums);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] nums) {
|
||||
if (path.size() == nums.length) {
|
||||
res.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
// used[i - 1] == false,说明同⼀树层nums[i - 1]使⽤过
|
||||
// 如果同⼀树层nums[i - 1]使⽤过则直接跳过
|
||||
// 一层
|
||||
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
|
||||
continue;
|
||||
}
|
||||
// used[i] == true,说明同⼀树⽀nums[i]使⽤过
|
||||
// 这个路径上被使用过
|
||||
// 一条路径
|
||||
if (used[i]) {
|
||||
continue;
|
||||
}
|
||||
used[i] = true;
|
||||
path.add(nums[i]);
|
||||
backTracking(nums);
|
||||
used[i] = false;
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/18 16:41
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode491 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
new Solution().findSubsequences(new int[]{4,6,7,5,7}).forEach(list -> {
|
||||
System.out.println(list);
|
||||
});
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> path = new ArrayList<>();
|
||||
public List<List<Integer>> findSubsequences(int[] nums) {
|
||||
|
||||
backTracking(nums, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] nums, int index) {
|
||||
|
||||
if (path.size() > 1) {
|
||||
// 插入res
|
||||
res.add(new ArrayList<>(path));
|
||||
}
|
||||
|
||||
Set<Integer> set = new HashSet<>();
|
||||
for (int i = index; i < nums.length; i++) {
|
||||
// 如果不满足非递减,即递增,这个子树不保留
|
||||
if ((!path.isEmpty() && path.get(path.size() - 1) > nums[i]) // 递增
|
||||
|| set.contains(nums[i]) // 如[4,7,xx,7],[4,7]已经出现在path中,7加入了set,那么在本层后面遇到7的时候,就直接continues
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
set.add(nums[i]);
|
||||
path.add(nums[i]);
|
||||
backTracking(nums, i + 1);
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/20 12:03
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode51 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
new Solution().solveNQueens(4).forEach(
|
||||
list -> {
|
||||
for (String s : list) {
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
List<List<String>> res = new ArrayList<>();
|
||||
|
||||
// 地图
|
||||
char[][] chessMap = null;
|
||||
|
||||
/**
|
||||
* 1. 形成棋盘
|
||||
* 2. 选择点进行填充
|
||||
* 填充后,判断该点上列、斜45、45度角是否有被使用过
|
||||
* - 如果有,回溯到上次递归
|
||||
* - 没有,标记该点Q,去下一行row+1进行填充
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public List<List<String>> solveNQueens(int n) {
|
||||
chessMap = new char[n][n];
|
||||
for (char[] c : chessMap) {
|
||||
Arrays.fill(c, '.');
|
||||
}
|
||||
backTracking(n, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int n, int row) {
|
||||
if (row == n) {
|
||||
List<String> element = new ArrayList<>();
|
||||
for (char[] chars : chessMap) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (char aChar : chars) {
|
||||
s.append(aChar);
|
||||
}
|
||||
element.add(s.toString());
|
||||
}
|
||||
res.add(element);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int col = 0; col < n; col++) {
|
||||
if (isValid(n, col, row)) {
|
||||
|
||||
chessMap[row][col] = 'Q';
|
||||
backTracking(n, row + 1);
|
||||
// 回溯
|
||||
chessMap[row][col] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否有效
|
||||
*
|
||||
* @param n n皇后
|
||||
* @param col 列
|
||||
* @param row 行
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid(int n, int col, int row) {
|
||||
// 判断某列是否有被使用过的,其实只要该点往上搜索就可以,下面的必定为.
|
||||
for (int i = 0; i < row; i++) {
|
||||
if (chessMap[i][col] == 'Q') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 判断45度 该点左上搜索
|
||||
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
|
||||
// 只要让某个点,不断往斜45度向左上检查就可以
|
||||
if (chessMap[i][j] == 'Q') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 判断斜45、135度 该点右边上搜索
|
||||
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
|
||||
// 只要让某个点,不断往斜45度向左上检查就可以
|
||||
if (chessMap[i][j] == 'Q') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/21 14:13
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode567 {
|
||||
|
||||
/**
|
||||
* 超时
|
||||
*/
|
||||
@Test
|
||||
public void test() {
|
||||
String s1 = "adc";
|
||||
String s2 = "dcda";
|
||||
boolean result = new Solution().checkInclusion(s1, s2);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
|
||||
/**
|
||||
* @param s1
|
||||
* @param s2
|
||||
* @return
|
||||
*/
|
||||
public boolean checkInclusion(String s1, String s2) {
|
||||
// 获取s1的全部排列,再到s2中找有没有对于的子串
|
||||
List<String> stringSub = getStringSub(s1);
|
||||
for (String s : stringSub) {
|
||||
int len = s1.length();
|
||||
for (int i = 0; i <= s2.length() - len; i++) {
|
||||
if (s2.substring(i, i + len).equals(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<String> getStringSub(String s1) {
|
||||
ArrayList<String> res = new ArrayList<>();
|
||||
backTracking(res, s1);
|
||||
return res;
|
||||
}
|
||||
|
||||
StringBuilder path = new StringBuilder();
|
||||
Set<Integer> set = new HashSet<>();
|
||||
public void backTracking(List<String> res, String s) {
|
||||
if (path.length() >= s.length()) {
|
||||
res.add(path.toString());
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (set.contains(i)) {
|
||||
continue;
|
||||
}
|
||||
set.add(i);
|
||||
path.append(s.charAt(i));
|
||||
backTracking(res, s);
|
||||
path.deleteCharAt(path.length() - 1);
|
||||
set.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
String s1 = "ab";
|
||||
String s2 = "eidboaooo";
|
||||
boolean result = new Solution1().checkInclusion(s1, s2);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* 需要同时考虑 s1的map和s2的map匹配,同时还有已经完全匹配的个数;
|
||||
* @param s1
|
||||
* @param s2
|
||||
* @return
|
||||
*/
|
||||
public boolean checkInclusion(String s1, String s2) {
|
||||
Map<Character, Integer> need = new HashMap<>();
|
||||
for (int i = 0; i < s1.length(); i++) {
|
||||
need.put(s1.charAt(i), need.getOrDefault(s1.charAt(i), 0) + 1);
|
||||
}
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
Map<Character, Integer> window = new HashMap<>();
|
||||
|
||||
int validCount = 0; // 记录有效个数(某个字符对应的数量和need一致),如果==need.size直接返回
|
||||
char[] s2CharArray = s2.toCharArray();
|
||||
while (right < s2.length()) {
|
||||
// 右边指针不断探,加入window统计出现个数
|
||||
char c = s2CharArray[right];
|
||||
right++;
|
||||
if (need.containsKey(c)) {
|
||||
window.put(c, window.getOrDefault(c, 0) + 1);
|
||||
if (window.get(c).equals(need.get(c))) {
|
||||
validCount++;
|
||||
if (validCount == need.size()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 左边指针收缩 关键在于找到进入while left 的循环条件
|
||||
while (right - left >= s1.length()) {
|
||||
char cha = s2CharArray[left];
|
||||
left++;
|
||||
if (need.containsKey(cha)) {
|
||||
if (window.get(cha).equals(need.get(cha))) {
|
||||
validCount--;
|
||||
}
|
||||
window.put(cha, window.get(cha) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/15 14:51
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode698 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {4, 3, 2, 3, 5, 2, 1};
|
||||
int k = 4;
|
||||
System.out.println(new Solution().canPartitionKSubsets(nums, k));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
public int[] numUsed;
|
||||
public boolean canPartitionKSubsets(int[] nums, int k) {
|
||||
numUsed = new int[nums.length];
|
||||
Arrays.sort(nums);
|
||||
int sum = Arrays.stream(nums).sum();
|
||||
if (sum % k != 0 || nums[nums.length - 1] > sum / k)
|
||||
return false;
|
||||
|
||||
return divideGroups(nums, nums.length - 1, sum / k, 0, k);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nums
|
||||
* @param start
|
||||
* @param target
|
||||
* @param current
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public boolean divideGroups(int[] nums, int start, int target, int current, int k) {
|
||||
if (k == 1)
|
||||
return true; // 分组操作执行k-1次之后,最后剩余的元素,就是最后一组了,不需要再匹配
|
||||
if (current == target)
|
||||
return divideGroups(nums, nums.length - 1, target, 0, k - 1); // 分组操作执行k-1次后,最后剩余的元素,就是最后一组了,不需要再匹配
|
||||
for (int i = start; i >= 0; i--) {
|
||||
if (numUsed[i] == 1 || current + nums[i] > target) continue; // 被使用的元素,不能再次使用;总和大于目标值,也不能使用
|
||||
|
||||
|
||||
numUsed[i] = 1; // 标记占用
|
||||
if (divideGroups(nums, i - 1, target, current + nums[i], k)) return true;
|
||||
numUsed[i] = 0; // 撤销标记
|
||||
|
||||
|
||||
while (i > 0 && nums[i - 1] == nums[i]) i--; // 例如“12333333...”,假如最右侧的“3”这个值没有匹配上,那么它左侧的剩余五个“3”都不需要再匹配了。
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/1/31 20:24
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode77 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
new Solution().combine(4, 4).forEach(
|
||||
list -> {
|
||||
list.forEach(System.out::print);
|
||||
System.out.println();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
List<List<Integer>> res = new LinkedList<>();
|
||||
|
||||
List<Integer> path = new ArrayList<>();
|
||||
|
||||
public List<List<Integer>> combine(int n, int k) {
|
||||
circle(1, n, k);
|
||||
return res;
|
||||
}
|
||||
|
||||
void circle(int start, int end, int k) {
|
||||
if (path.size() == k) {
|
||||
res.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
|
||||
// 剪枝,可以选择的个数不满足最小需要的个数
|
||||
// 已经选择的个数 path.size
|
||||
// 还需要的个数 k-path.size
|
||||
// 可以选择的个数<还需要的个数 end-i<k-path.size 时 退出
|
||||
// 即 end-i>k-path.size时正常执行 i<end-(k-path.size) 时正常执行
|
||||
for (int i = start; i <= end - (k - path.size()) + 1; i++) {
|
||||
path.add(i);
|
||||
circle(i + 1, end, k);
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/18 10:29
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode78 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution().subsets(new int[]{1, 2, 3}));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> temp = new ArrayList<>();
|
||||
public List<List<Integer>> subsets(int[] nums) {
|
||||
backTracking(nums, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
void backTracking(int[] nums, int start) {
|
||||
res.add(new ArrayList<>(temp));
|
||||
if (start >= nums.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = start; i < nums.length ; i++) {
|
||||
temp.add(nums[i]);
|
||||
backTracking(nums,i+1);
|
||||
temp.remove(temp.size() - 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/18 13:26
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode90 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
new Solution().subsetsWithDup(new int[]{1, 2, 2}).forEach(
|
||||
list -> {
|
||||
System.out.println(list);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
List<Integer> temp = new ArrayList<>();
|
||||
boolean[] used = null;
|
||||
public List<List<Integer>> subsetsWithDup(int[] nums) {
|
||||
Arrays.sort(nums);
|
||||
used = new boolean[nums.length];
|
||||
backTracking(nums, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
void backTracking(int[] nums, int start) {
|
||||
res.add(new ArrayList<>(temp));
|
||||
if (start >= nums.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (int i = start; i < nums.length ; i++) {
|
||||
|
||||
// 1. u1 u2 相同,并且u1曾经被调用过,则不继续进行本次循环
|
||||
// if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
|
||||
// continue;
|
||||
// }
|
||||
// 2. 不使用used数组,跳过当前树层使用过的、相同的元素
|
||||
if ( i > start && nums[i - 1] == nums[i] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
temp.add(nums[i]);
|
||||
used[i] = true;
|
||||
backTracking(nums,i+1);
|
||||
temp.remove(temp.size() - 1);
|
||||
used[i] = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
package cn.whaifree.leetCode.BackTracking;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/18 9:27
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode93 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
for (String restoreIpAddress : new Solution1().restoreIpAddresses("101023")) {
|
||||
System.out.println(restoreIpAddress);
|
||||
}
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
List<String> res = new ArrayList<>();
|
||||
List<String> path = new ArrayList<>();
|
||||
public List<String> restoreIpAddresses(String s) {
|
||||
backTracking(s, 0, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param s
|
||||
* @param start 递归开始标记
|
||||
* @param number 这是第几个切片,4个切片为一组有效返回
|
||||
*/
|
||||
public void backTracking(String s, int start,int number) {
|
||||
// 如果 第5个切片了,则存在多余的字符,直接return
|
||||
if (number > 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (start >= s.length() && path.size() == 4) {
|
||||
res.add(String.join(".", path));
|
||||
|
||||
// StringBuilder stringBuilder = new StringBuilder();
|
||||
// for (int i = 0; i < path.size() - 1; i++) {
|
||||
// stringBuilder.append(path.get(i)).append(".");
|
||||
// }
|
||||
// stringBuilder.append(path.get(path.size() - 1));
|
||||
// res.add(stringBuilder.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = start; i < s.length() ; i++) {
|
||||
|
||||
if (isValid(s, start, i + 1)) {
|
||||
|
||||
path.add(s.substring(start, i + 1));
|
||||
backTracking(s, i + 1, number + 1);
|
||||
path.remove(path.size() - 1);
|
||||
}else {
|
||||
// 2565 256无效,那么2565直接就无效了
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValid(String s, int start, int end) {
|
||||
String substring = s.substring(start, end);
|
||||
// 子串最多不超过3个字符
|
||||
if (substring.length() > 3 ) {
|
||||
return false;
|
||||
}
|
||||
// “01”为非法,"0"为合法
|
||||
if (substring.length() != 1 && substring.startsWith("0")) {
|
||||
return false;
|
||||
}
|
||||
int integer = Integer.parseInt(substring);
|
||||
if (integer >= 0 && integer <= 255) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过char进行字符串转为int
|
||||
* @param s
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
private boolean isValid(StringBuilder s, int start, int end){
|
||||
if(start > end)
|
||||
return false;
|
||||
if(s.charAt(start) == '0' && start != end)
|
||||
return false;
|
||||
int num = 0;
|
||||
for(int i = start; i <= end; i++){
|
||||
int digit = s.charAt(i) - '0';
|
||||
num = num * 10 + digit;
|
||||
if(num > 255)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Solution1 {
|
||||
|
||||
List<String> res = new ArrayList<>();
|
||||
List<String> path = new ArrayList<>();
|
||||
public List<String> restoreIpAddresses(String s) {
|
||||
backTracking(s, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param s
|
||||
* @param start 递归开始标记
|
||||
*/
|
||||
public void backTracking(String s, int start) {
|
||||
|
||||
if (start >= s.length() && path.size() == 4) {
|
||||
res.add(String.join(".", path));
|
||||
|
||||
// StringBuilder stringBuilder = new StringBuilder();
|
||||
// for (int i = 0; i < path.size() - 1; i++) {
|
||||
// stringBuilder.append(path.get(i)).append(".");
|
||||
// }
|
||||
// stringBuilder.append(path.get(path.size() - 1));
|
||||
// res.add(stringBuilder.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = start; i < s.length() ; i++) {
|
||||
|
||||
if (isValid(s, start, i + 1)) {
|
||||
|
||||
path.add(s.substring(start, i + 1));
|
||||
backTracking(s, i + 1);
|
||||
path.remove(path.size() - 1);
|
||||
}else {
|
||||
// 2565 256无效,那么2565直接就无效了
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValid(String s, int start, int end) {
|
||||
String substring = s.substring(start, end);
|
||||
// 子串最多不超过3个字符
|
||||
if (substring.length() > 3 ) {
|
||||
return false;
|
||||
}
|
||||
// “01”为非法,"0"为合法
|
||||
if (substring.length() != 1 && substring.startsWith("0")) {
|
||||
return false;
|
||||
}
|
||||
int integer = Integer.parseInt(substring);
|
||||
if (integer >= 0 && integer <= 255) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/26 13:30
|
||||
* @注释
|
||||
*/
|
||||
public class AbsoluteBeiBao {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] weight = {1, 3, 4};
|
||||
int[] value = {15, 20, 30};
|
||||
int capacity = 4;
|
||||
System.out.println(absoluteBeiBaoOneD(weight, value, capacity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用动态规划解决背包问题,求解在给定背包容量下,能够获得的最大价值。
|
||||
* @param weight 物品的重量数组
|
||||
* @param value 物品的价值数组
|
||||
* @param capacity 背包的容量
|
||||
*/
|
||||
public int absoluteBeiBao(int[] weight, int[] value,int capacity) {
|
||||
|
||||
int length = weight.length;
|
||||
int[][] dp = new int[length + 1][capacity + 1];
|
||||
|
||||
// 初始化动态规划数组
|
||||
// dp[i][j] 表示在前 i 个物品【0-(i-1)】中,背包容量为 j 的情况下的最大价值。
|
||||
for (int i = 1; i <= length; i++) { //
|
||||
for (int j = 1; j <= capacity; j++) {
|
||||
if (j >= weight[i-1]) {
|
||||
// 当前物品重量小于等于背包容量时,考虑放入当前物品
|
||||
// 完全背包二维数组的代码跟一维只有下面一个下标不同,
|
||||
// 那就是“放i”这个选择,因为是可以重复放的,所以是dp[i]
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - weight[i-1]] + value[i-1]);
|
||||
}else {
|
||||
// 当前物品重量大于背包容量,无法放入,维持前一个状态
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[length][capacity];
|
||||
}
|
||||
|
||||
public int absoluteBeiBaoOneD(int[] weight, int[] value,int capacity) {
|
||||
|
||||
int length = weight.length;
|
||||
int[] dp = new int[capacity + 1];
|
||||
|
||||
// 初始化动态规划数组
|
||||
// dp[i][j] 表示在前 i 个物品【0-(i-1)】中,背包容量为 j 的情况下的最大价值。
|
||||
// dp[j] 表示前i个物品中,背包容量为j的最大价值
|
||||
for (int i = 1; i <= length; i++) { //
|
||||
for (int j = weight[i - 1]; j <= capacity; j++) {
|
||||
dp[j] = Math.max(dp[j], dp[j - weight[i - 1]] + value[i - 1]);
|
||||
}
|
||||
}
|
||||
return dp[capacity];
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/12 16:53
|
||||
* @注释
|
||||
*/
|
||||
public class BeiBao {
|
||||
|
||||
@Test
|
||||
public void main() {
|
||||
//
|
||||
// new Thread(() -> {
|
||||
// try {
|
||||
// Thread.sleep(1000);
|
||||
// } catch (InterruptedException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// }).start();
|
||||
//
|
||||
// new Thread(() -> {
|
||||
//
|
||||
// }).start();
|
||||
//
|
||||
//
|
||||
// String a = "a";
|
||||
//
|
||||
// String b = new String("a");
|
||||
//
|
||||
// System.out.println(a == b);
|
||||
int[] weight = {1,3,4};
|
||||
int[] value = {15,20,30};
|
||||
int bagSize = 4;
|
||||
new Solution2().packageProblem(weight, value, bagSize);
|
||||
}
|
||||
|
||||
class Solution{
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <br/>
|
||||
* <img src='https://code-thinking-1253855093.file.myqcloud.com/pics/2021011010314055.png' />
|
||||
*
|
||||
* @param weights 每个物品的重量
|
||||
* @param values 每个物品的价值
|
||||
* @param carryNumber 允许携带的数量
|
||||
* @return 价值
|
||||
*/
|
||||
public int packageProblem(int[] weights, int[] values, int carryNumber) {
|
||||
/**
|
||||
* 重量 价值
|
||||
* 物品0 1 15
|
||||
* 物品1 3 20
|
||||
* 物品2 4 30
|
||||
*/
|
||||
// dp[i][j] i表示携带的产品,j表示容量为j的背包 dp[i][j]为从0-i个产品里取,最大的价值
|
||||
// 1. 不放物品i的最大价值,dp[i][j] = dp[i-1][j] 不放物品i,所以i不占重量,所以不用-weight[i]
|
||||
// 2. 放物品i的最大价值 dp[i-1][j-weight[i]] + value[i] 如果放了物品i,那最大价值就 不放物品i的最大价值+物品i的价值(j-weight[i] 表示放i需要腾出来空间)
|
||||
// dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,注意是不放物品i,所以要减去weight[i]
|
||||
// dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]); 不放物品的价值 加上i物品的价值
|
||||
|
||||
// 初始化:如果容量为0,最大价值都为0;如果容量为1、2、3,只能放物品0的时候,最大价值都是15
|
||||
int goodsNumber = weights.length;
|
||||
int[][] dp = new int[goodsNumber][carryNumber + 1];
|
||||
// 把第0个物品进行初始化,前提是能够放入第0个物品
|
||||
for (int i = weights[0]; i < carryNumber + 1; i++) {
|
||||
dp[0][i] = values[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 先遍历物品,再遍历背包
|
||||
*/
|
||||
for (int i = 1; i < goodsNumber; i++) {
|
||||
for (int j = 1; j < carryNumber + 1; j++) {
|
||||
if (weights[i] > j) {
|
||||
// 物品i放不进背包容量为j的背包
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
}else {
|
||||
// 能放进去
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i]] + values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 打印dp数组
|
||||
for (int i = 0; i < goodsNumber; i++) {
|
||||
for (int j = 0; j <= carryNumber; j++) {
|
||||
System.out.print(dp[i][j] + "\t");
|
||||
}
|
||||
System.out.println("\n");
|
||||
}
|
||||
|
||||
return dp[weights.length - 1][carryNumber];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Solution1{
|
||||
|
||||
/**
|
||||
* dp[i][j] i表示商品,j表示空间 dp[i][j]表示 容量为j为包裹,从0-i个商品中取得最大值
|
||||
*
|
||||
* 初始化
|
||||
* 0 1 2 3 4 5 包容量
|
||||
* 物品0 0 0 2 2 2 2
|
||||
* 物品1 0
|
||||
* 物品2 0
|
||||
*
|
||||
* dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
|
||||
*
|
||||
* @param weights 物品的重量
|
||||
* @param values 物品的价值
|
||||
* @param carryNumber 可以携带的数量
|
||||
* @return
|
||||
*/
|
||||
public int packageProblem(int[] weights, int[] values, int carryNumber) {
|
||||
int length = weights.length;
|
||||
int[][] dp = new int[length][carryNumber + 1];
|
||||
for (int i = 0; i < length; i++) {
|
||||
dp[i][0] = 0;
|
||||
}
|
||||
for (int i = weights[0]; i <= carryNumber; i++) {
|
||||
dp[0][i] = values[0];
|
||||
}
|
||||
|
||||
// 如果i 不放东西 dp[i][j] = dp[i-1][j]
|
||||
// 如果i 放东西 dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]-value[i])
|
||||
|
||||
// i为商品;j为容量。
|
||||
for (int i = 1; i < length; i++) {
|
||||
for (int j = 1; j <= carryNumber; j++) {
|
||||
if (weights[i] > j) {
|
||||
// 重量太大,放不进去
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
}else {
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i]] + values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return dp[length - 1][carryNumber];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Solution2{
|
||||
|
||||
/**
|
||||
*
|
||||
* dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
|
||||
* dp[j] 表示容量为j的背包的最大价值总和
|
||||
*
|
||||
* 初始化
|
||||
* 0 1 2 3 4 5 包容量
|
||||
* 物品0 0 0 2 2 2 2
|
||||
* 物品1 0
|
||||
* 物品2 0
|
||||
*
|
||||
* 不放这个商品 那价值不变,还是dp[j]
|
||||
* dp[j] = max(dp[j] , dp[j-weight[i]]+value[i]])
|
||||
*
|
||||
* @param weights 物品的重量
|
||||
* @param values 物品的价值
|
||||
* @param carryNumber 可以携带的数量
|
||||
* @return
|
||||
*/
|
||||
public int packageProblem(int[] weights, int[] values, int carryNumber) {
|
||||
int length = weights.length;
|
||||
int[] dp = new int[carryNumber + 1];
|
||||
|
||||
// 不放这个商品 那价值不变,还是dp[j]
|
||||
// dp[j] = max(dp[j] , dp[j-weight[i]]+value[i]])
|
||||
|
||||
// i为商品;j为容量。
|
||||
for(int i = 0; i < length; i++) { // 遍历物品
|
||||
for(int j = carryNumber ;j >= weights[i]; j--) { // 遍历背包容量
|
||||
dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
|
||||
}
|
||||
/**
|
||||
* 倒序遍历是为了保证物品i只被放入一次!。但如果一旦正序遍历了,那么物品0就会被重复加入多次!
|
||||
*
|
||||
* 举一个例子:物品0的重量weight[0] = 1,价值value[0] = 15
|
||||
* 如果正序遍历
|
||||
* dp[1] = dp[1 - weight[0]] + value[0] = 15
|
||||
* dp[2] = dp[2 - weight[0]] + value[0] = 30
|
||||
*
|
||||
* 此时dp[2]就已经是30了,意味着物品0,被放入了两次,所以不能正序遍历。
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
return dp[carryNumber];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/27 12:45
|
||||
* @注释
|
||||
*/
|
||||
public class KaMa47 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
|
||||
int i = new Solution().plt(3, 2);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
/* https://kamacoder.com/problempage.php?pid=1067
|
||||
*/
|
||||
class Solution{
|
||||
|
||||
public static void main(String[] args) {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
int capacity = scanner.nextInt();
|
||||
int m = scanner.nextInt();
|
||||
System.out.println(plt(capacity, m));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param capacity 需要n阶
|
||||
* @param m 每一步可以走几个
|
||||
* @return
|
||||
*/
|
||||
public static int plt(int capacity, int m) {
|
||||
|
||||
// 排列
|
||||
int[] dp = new int[capacity + 1];
|
||||
|
||||
dp[0] = 1;
|
||||
for (int j = 0; j <= capacity; j++) {
|
||||
for (int i = 1; i <= m; i++) {
|
||||
if (j >= i) {
|
||||
dp[j] += dp[j - i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[capacity];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/25 11:28
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode1035 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums1 = new int[]{1,3,7,1,7,5};
|
||||
int[] nums2 = new int[]{1,9,2,5,1};
|
||||
System.out.println(new Solution().maxUncrossedLines(nums1, nums2));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 不相交,就是挨个求nums1的子序列在nums中出现的次数
|
||||
* - 不用连续
|
||||
* - 子序列
|
||||
*
|
||||
* dp[i][j] 表示 nums1从0-i-1,nums2从0-j-1,有几个相同的子序列
|
||||
*
|
||||
* if nums1[i] == nums2[j]
|
||||
* dp[i][j] = dp[i-1][j-1]+1
|
||||
* else
|
||||
* dp[i][j] = dp[i-1][j-1]
|
||||
*
|
||||
*
|
||||
* @param nums1 短的
|
||||
* @param nums2 长的
|
||||
* @return
|
||||
*/
|
||||
public int maxUncrossedLines(int[] nums1, int[] nums2) {
|
||||
if (nums1.length > nums2.length) {
|
||||
return maxUncrossedLines(nums2, nums1);
|
||||
}
|
||||
int[][] dp = new int[nums1.length + 1][nums2.length + 1];
|
||||
|
||||
for (int i = 1; i <= nums1.length; i++) {
|
||||
for (int j = 1; j <= nums2.length; j++) {
|
||||
if (nums1[i - 1] == nums2[j - 1]) {
|
||||
// 对应位置相等,则从i-1 j-1的值+1
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
// 对应的值不相等,则获取前面已经匹配的最大值
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[nums1.length][nums2.length];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/18 14:31
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode1049 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] stones = {1,2};
|
||||
int result = new Solution1().lastStoneWeightII(stones);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 背包容量为half,让其尽可能装满,除非装不下了。到装不下了,这一部分已经装入的就是拿来碰撞的。剩下就是sum-dp[half]-dp[half]
|
||||
*
|
||||
* 目标就是让石头的总价值分为两部分
|
||||
*
|
||||
* 转换为背包问题
|
||||
*
|
||||
* dp[j] 表示 容量为j的背包最多能够容纳多少价值的物品
|
||||
* - 物品i的价值 为 stones[i]
|
||||
* - 物品i的重量 为 stones[i]
|
||||
*
|
||||
* 1 <= stones.length <= 30
|
||||
* 1 <= stones[i] <= 100
|
||||
* 初始化为store[half]
|
||||
*
|
||||
*
|
||||
* 递推公式 dp[j] = Math.max(dp[j],dp[j-weight[i]]+value[i])
|
||||
* 分成两堆石头,一堆石头的总重量是dp[half],另一堆就是sum - dp[half]。
|
||||
*
|
||||
* @param stones
|
||||
* @return
|
||||
*/
|
||||
public int lastStoneWeightII(int[] stones) {
|
||||
int sum = 0;
|
||||
for (int stone : stones) {
|
||||
sum += stone;
|
||||
}
|
||||
|
||||
int half = sum / 2;
|
||||
int[] dp = new int[half + 1];
|
||||
for (int i = 0; i < stones.length; i++) {
|
||||
for (int j = half; j >= stones[i]; j--) { // 确保背包能够放下
|
||||
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// dp[half] 是要被消灭的,那两个部分的消灭就*2
|
||||
return sum - dp[half] * 2;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* half = sum/2
|
||||
*
|
||||
*
|
||||
* dp[i][j] 表示 放入i后,容量为j的背包的最大价值
|
||||
*
|
||||
* 1. 放入i dp[i][j] = dp[i-1][j-weight[i]]+value[i]
|
||||
* 2. 不放入i dp[i][j] = dp[i-1][j]
|
||||
*
|
||||
* 2 4 1 1 target=4
|
||||
*
|
||||
* 0 1 2 3 4
|
||||
* 0 0 0 2 2 2
|
||||
* 1 0 0 2 2 2
|
||||
* 2 0 1 3 3 3
|
||||
* 3 0 1 4 4 4
|
||||
*
|
||||
* @param stones
|
||||
* @return
|
||||
*/
|
||||
public int lastStoneWeightII(int[] stones) {
|
||||
int sum = 0;
|
||||
for (int stone : stones) {
|
||||
sum += stone;
|
||||
}
|
||||
// 计算所有石头的总重量,并将其的一半作为目标重量
|
||||
int half = sum / 2;
|
||||
|
||||
int length = stones.length;
|
||||
int[][] dp = new int[length][half + 1];
|
||||
|
||||
for (int i = stones[0]; i <= half; i++) {
|
||||
dp[0][i] = stones[0];
|
||||
}
|
||||
for (int i = 1; i < length; i++) {
|
||||
for (int j = 1; j <= half ; j++) {
|
||||
if (j < stones[i]) {
|
||||
// 放不下 就不放了,价值为i-1物品的最大价值
|
||||
// 当前石头重量大于目标重量,无法放入,价值等于前i-1个石头的最大价值
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
}else {
|
||||
// 取放入和不放入当前石头两种情况中的最大价值
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回石头总重量减去最接近目标重量的那堆石头的两倍重量
|
||||
return sum - dp[length - 1][half] * 2;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/24 12:00
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode1143 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Solution solution = new Solution();
|
||||
int res = solution.longestCommonSubsequence("bsbininm","jmjkbkjkv" );
|
||||
System.out.println(res);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int longestCommonSubsequence(String text1, String text2) {
|
||||
|
||||
// 公共子序列 dp[len1+1][len2+1]
|
||||
// dp[i][j] 表示 text1的前i-1与text2的前j-1中有多长的公共子序列长度
|
||||
// dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
|
||||
// if text1[i]==text2[i]
|
||||
//
|
||||
//
|
||||
int len1 = text1.length();
|
||||
int len2 = text2.length();
|
||||
|
||||
int[][] dp = new int[len1 + 1][len2 + 1];
|
||||
|
||||
for (int i = 1; i <= len1; i++) {
|
||||
for (int j = 1; j <= len2; j++) {
|
||||
// 如果相等
|
||||
if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
//dp[i][j] = Math.max(dp[i][j - 1] + 1, dp[i][j]);
|
||||
} else {
|
||||
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
|
||||
// dp[i][j] = Math.max(dp[i - 1][j - 1], Math.max(dp[i - 1][j], dp[i][j - 1]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return dp[len1][len2];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/26 11:44
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode115 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
Solution solution = new Solution();
|
||||
System.out.println(solution.numDistinct("rabbbit", "rabbit"));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int numDistinct(String s, String t) {
|
||||
/**
|
||||
* dp[i][j] 以i-1为 结尾的 s子序列 中出现以j-1为 结尾的 t的个数为dp[i][j]
|
||||
*
|
||||
* '' b a g
|
||||
* '' 1 0 0 0
|
||||
* b 1 1 0 0
|
||||
* a 1 1 1 0
|
||||
* e 1 1 1 0
|
||||
* g 1 1 1 1
|
||||
* g 1 1 1 2
|
||||
*
|
||||
* if s[i]==t[j]
|
||||
* 1. 用s[i - 1]来匹配 dp[i - 1][j - 1] bagg和bag t匹配到s的第二个g时,使用第一个g
|
||||
* 2. 不用第s[i - 1]来匹配 dp[i - 1][j] bagg和bag t匹配到s的第二个g时,不使用第一个g
|
||||
* dp[i][j] = dp[i-1][j-1]+dp[i - 1][j];
|
||||
* else
|
||||
* 不用s[i - 1]来匹配,模拟s中删除了这个元素
|
||||
* dp[i][j] = dp[i - 1][j];
|
||||
*
|
||||
*/
|
||||
|
||||
char[] sChar = s.toCharArray();
|
||||
char[] tChar = t.toCharArray();
|
||||
int[][] dp = new int[sChar.length + 1][tChar.length + 1];
|
||||
for (int i = 0; i < sChar.length; i++) {
|
||||
dp[i][0] = 1;
|
||||
}
|
||||
for (int i = 1; i <= sChar.length; i++) {
|
||||
for (int j = 1; j <= tChar.length; j++) {
|
||||
if (sChar[i - 1] == tChar[j - 1]) {
|
||||
// 如果相同
|
||||
// 使用i-1进行匹配 dp[i - 1][j - 1] bagg和bag t匹配到s的第二个g时,使用第一个g
|
||||
// 不用第s[i - 1]来匹配 dp[i - 1][j] bagg和bag t匹配到s的第二个g时,不使用第一个g
|
||||
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
|
||||
} else {
|
||||
// 不用s[i - 1]来匹配
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[sChar.length][tChar.length];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/3 14:38
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode121 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
|
||||
int[] prices = {7,1,5,3,6,4};
|
||||
System.out.println(new Solution1().maxProfit(prices));
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
*
|
||||
* 只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。
|
||||
*
|
||||
* dp[i][1]表示i天不持有股票的持有现金
|
||||
* dp[i][0]表示i天持有股票所有的现金
|
||||
* 第i天买入股票现金就是 -prices[i]
|
||||
*
|
||||
* 第i天有股票 1. 刚刚买入、2. 第i-1天就有
|
||||
* 第i天没有股票 2. 第i天卖出 2. 第i-1天就没有股票
|
||||
*
|
||||
* dp[i][0] 持有股票
|
||||
* - i-1就持有股票,今天不卖 dp[i-1][0]
|
||||
* - 买入股票 -今天的股价 -prices[i]
|
||||
* - max
|
||||
* dp[i][1] 无持有
|
||||
* - i-1 保持现状dp[i-1][1]
|
||||
* - 卖出 prices[i] + dp[i-1][0] 价格+[i-1]天加持有的现金
|
||||
* - max
|
||||
* dp[0][0] = -price[0]
|
||||
* dp[0][1] = 0
|
||||
*
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices) {
|
||||
|
||||
if (prices.length == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int[] dp = new int[2];
|
||||
|
||||
dp[0] = -prices[0];
|
||||
dp[1] = 0;
|
||||
for (int i = 0; i < prices.length; i++) {
|
||||
// 持有股票 1. i-1就有 2. 刚刚买入
|
||||
dp[0] = Math.max(dp[0], -prices[i]);
|
||||
// 无股票 2. i-1就无,2 刚刚卖出
|
||||
dp[1] = Math.max(dp[1], dp[0] + prices[i]);
|
||||
}
|
||||
return dp[1]; // 最后一天一定没有股票才能有最大利润
|
||||
}
|
||||
}
|
||||
class Solution1 {
|
||||
/**
|
||||
* 贪心
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices) {
|
||||
|
||||
int min = Integer.MAX_VALUE;
|
||||
int res = 0;
|
||||
for (int i = 0; i < prices.length; i++) {
|
||||
min = Math.min(min, prices[i]);
|
||||
res = Math.max(res, prices[i] - min);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/28 13:15
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode139 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// System.out.println(new Solution().wordBreak("leetcode", List.of("leet", "code")));
|
||||
// System.out.println(new Solution().wordBreak("leetcode", List.of("leet", "cod", "e")));
|
||||
// ["apple","pen"]
|
||||
System.out.println(new Solution().wordBreak("applepenapple", List.of("apple", "pen")));
|
||||
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
*
|
||||
* dp[i][j] 表示s中前j个字母能否被0-i中任意元素组合出来
|
||||
*
|
||||
* 定义 dp[i] 表示字符串 s 前 i 个字符组成的字符串 s[0..i−1] 是否能被空格拆分成若干个字典中出现的单词
|
||||
*
|
||||
* c a t s a n d o g
|
||||
* cats 0 0 0 1 0
|
||||
* dog
|
||||
* sand
|
||||
* and
|
||||
* cat
|
||||
* '' l e e t c o d e
|
||||
* '' 1 0 0 0 0 0 0 0 0
|
||||
* leet 1 0 0 0 1 0 0 0 0
|
||||
* code 1 0 0 0 0 0 0 0 1
|
||||
*
|
||||
* a p p l e p e n a p p l e
|
||||
* apple 1 0 0 0 0 1 0 0 0 0 0 0 0 1
|
||||
* pen 1 0 0 0 0 1 0 0 1 0 0 0 0 0
|
||||
*
|
||||
* @param s
|
||||
* @param wordDict
|
||||
* @return
|
||||
*/
|
||||
public boolean wordBreak(String s, List<String> wordDict) {
|
||||
// 完全背包,先便利字符串再遍历背包,确保重会重复选择背包
|
||||
int len = s.length();
|
||||
boolean[] dp = new boolean[len + 1];
|
||||
dp[0] = true;
|
||||
for (int j = 1; j <= len; j++) {
|
||||
for (int i = 0; i < wordDict.size(); i++) {
|
||||
String str = wordDict.get(i);
|
||||
int index = j - str.length();
|
||||
if (index >= 0 && dp[index] && check(s, j - 1, str)) {
|
||||
dp[j] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[len];
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean check(String s, int start, String word) {
|
||||
for (int i = word.length() - 1; i >= 0; i--) {
|
||||
if (word.charAt(i) != s.charAt(start)) {
|
||||
return false;
|
||||
}
|
||||
start--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void main() {
|
||||
System.out.println(new Solution().check("leetcode", 7, "code"));
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/3 13:50
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode198 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
Solution solution = new Solution();
|
||||
int[] nums = new int[]{2,7};
|
||||
int rob = solution.rob(nums);
|
||||
System.out.println(rob);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int rob(int[] nums) {
|
||||
if (nums.length == 1) {
|
||||
return nums[0];
|
||||
}
|
||||
// dp[i] 表示 从0-i偷窃都最大价值
|
||||
// dp[i] = max(dp[i-1],dp[i-2]+nums[i]])
|
||||
int[] dp = new int[nums.length];
|
||||
dp[0] = nums[0];
|
||||
dp[1] = Math.max(nums[0], nums[1]);
|
||||
for (int i = 2; i < nums.length; i++) {
|
||||
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
|
||||
}
|
||||
return dp[nums.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/28 11:53
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode279 {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
Solution solution = new Solution();
|
||||
int numSquares = solution.numSquares(12);
|
||||
System.out.println(numSquares);
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
public int numSquares(int n) {
|
||||
|
||||
// 完全平方数 任意取,使其满足n容量的背包的最少数量
|
||||
// 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
|
||||
// dp[j] 表示容量为j的背包 最少 需要的 完全平方数 的数量
|
||||
|
||||
int[] dp = new int[n + 1];
|
||||
Arrays.fill(dp, Integer.MAX_VALUE);
|
||||
|
||||
|
||||
// 求组合数就是外层for循环遍历物品,内层for遍历背包
|
||||
// 求排列数就是外层for遍历背包,内层for循环遍历物品 {1,0} {0,1}
|
||||
// 本题都可以
|
||||
dp[0] = 0;
|
||||
// for (int j = 0; j <= n; j++) {
|
||||
// for (int i = 1; i * i <= j; j++) {
|
||||
// // i-j*j 表示 之前的完全平方数 + 这个挖
|
||||
// dp[j] = Math.min(dp[j - i * i] + 1, dp[j]);
|
||||
// }
|
||||
// }
|
||||
|
||||
for (int i = 1; i * i <= n; i++) {
|
||||
for (int j = i * i; j <= n; j++) {
|
||||
// i-j*j 表示 之前的完全平方数 + 这个挖
|
||||
dp[j] = Math.min(dp[j - i * i] + 1, dp[j]);
|
||||
//dp[j] 可以由dp[j - i * i]推出, dp[j - i * i] + 1 便可以凑成dp[j]。
|
||||
// 或者说, dp[j-i*i]表示j-i*i的最小需要平方数,加上我们给到的i*i这一个平方数,就是+1,即dp[j - i * i] + 1
|
||||
}
|
||||
}
|
||||
|
||||
return dp[n];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/22 13:23
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode300 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums = {4,10,4,3,8,9};
|
||||
Solution solution = new Solution();
|
||||
int i = solution.lengthOfLIS(nums);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* int[i][j] 表示i-j的最长严格递增子序列长度
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int lengthOfLIS(int[] nums) {
|
||||
int[] dp = new int[nums.length];
|
||||
|
||||
|
||||
// dp[i]表示i之前包括i的以(nums[i]结尾)(即每次都必须包括i,每次都需要和i比较)的最长递增子序列的长度
|
||||
// 位置i的最长升序子序列 = j从0到i-1各个位置的 最长升序子序列 + 1 的 最大值
|
||||
Arrays.fill(dp, 1);
|
||||
int res = 1;
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (nums[j] < nums[i]) {
|
||||
dp[i] = Math.max(dp[i], dp[j] + 1);
|
||||
}
|
||||
}
|
||||
|
||||
res = Math.max(res, dp[i]);// 取长的子序列
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Solution1 {
|
||||
|
||||
public int lengthOfLIS(int[] nums) {
|
||||
// 最长严格递增子序列的长度
|
||||
/**
|
||||
* dp[i] 表示包含从0-i包含i(i在每次循环中是最后一个)的最长递增子序列的长度
|
||||
*/
|
||||
int[] dp = new int[nums.length];
|
||||
Arrays.fill(dp, 1); // 最初就是1个
|
||||
|
||||
int res = 1;
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
// 从0到i-1
|
||||
// nums[j] < nums[i] 就证明 nums[j] 小于 nums[i] ,前面有多少个j就计算多少次
|
||||
if (nums[j] < nums[i]) {
|
||||
dp[i] = Math.max(dp[i], dp[j] + 1); // dp[i] 为0-(j-1)的最长递增子序列长度,dp[j] + 1 为0-j的最长递增子序列长度,取两者最大值
|
||||
}
|
||||
}
|
||||
res = Math.max(res, dp[i]); // 每次获得以i为最后一个的最长递增子序列的长度
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/27 12:58
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode322 {
|
||||
@Test
|
||||
public void test() {
|
||||
int[] coins = {1};
|
||||
int amount = 0;
|
||||
int i = new Solution1().coinChange(coins, amount);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int coinChange(int[] coins, int amount) {
|
||||
int[] dp = new int[amount + 1];
|
||||
Arrays.fill(dp, Integer.MAX_VALUE);
|
||||
|
||||
dp[0] = 0; // 总和为0的方案为0
|
||||
for (int i = 0; i < coins.length; i++) {
|
||||
for (int j = coins[i]; j <= amount ; j++) {
|
||||
//只有dp[j-coins[i]]不是初始最大值时,该位才有选择的必要
|
||||
if (dp[j - coins[i]] != Integer.MAX_VALUE) {
|
||||
//选择硬币数目最小的情况
|
||||
// 不放 和 放(加上本次方案1)
|
||||
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入:coins = [2], amount = 3
|
||||
* 输出:-1
|
||||
*/
|
||||
return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* 背包容量为amount
|
||||
* coins里随便取
|
||||
*
|
||||
* dp[j] 表示使用[0-i]任意硬币取凑出j的最小硬币数
|
||||
*
|
||||
* [1, 2, 5]
|
||||
* 0 1 2 3 4 5 6
|
||||
* 0 0 1 2 3 4 5 6
|
||||
* 1 0 1 1 2 2 3 3
|
||||
* 2
|
||||
* 3
|
||||
* 4
|
||||
*
|
||||
* dp[j] = math.min(dp[j],dp[j-coin[i]]+1)
|
||||
*
|
||||
* @param coins
|
||||
* @param amount
|
||||
* @return
|
||||
*/
|
||||
public int coinChange(int[] coins, int amount) {
|
||||
|
||||
|
||||
int[] dp = new int[amount+1];
|
||||
|
||||
|
||||
for (int i = 1; i < dp.length; i++) {
|
||||
dp[i] = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
|
||||
dp[0] = 0;
|
||||
for (int i = 0; i < coins.length; i++) {
|
||||
for (int j = coins[i]; j < amount + 1; j++) {
|
||||
if (dp[j - coins[i]] != Integer.MAX_VALUE) {
|
||||
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import cn.whaifree.leetCode.model.TreeNode;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/3 13:55
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode337 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
System.out.println(new Solution().rob(TreeNode.constructTreeByArray(4,1,null,2,null,3)));
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
public int rob(TreeNode root) {
|
||||
/**
|
||||
* dp[0]表示不选该点的最大收益 dp[1]表示选该节点的最大收益
|
||||
*
|
||||
*/
|
||||
int[] ints = robDown(root);
|
||||
return Math.max(ints[0], ints[1]);
|
||||
}
|
||||
|
||||
public int[] robDown(TreeNode root) {
|
||||
int res[] = new int[2];
|
||||
if (root == null) {
|
||||
return res;
|
||||
}
|
||||
int[] left = robDown(root.left);
|
||||
int[] right = robDown(root.right);
|
||||
|
||||
// 不偷:Max(左孩子不偷,左孩子偷) + Max(右孩子不偷,右孩子偷)
|
||||
// 不偷:左右随意,选最大的
|
||||
res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
|
||||
// 偷:左孩子不偷+ 右孩子不偷 + 当前节点偷
|
||||
// 偷:必须保证左右都不偷
|
||||
res[1] = left[0] + right[0] + root.val;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public int rob(TreeNode root) {
|
||||
// 两层,根节点用和不用
|
||||
return Math.max(robDown(root, true), robDown(root, false));
|
||||
}
|
||||
|
||||
public int robDown(TreeNode root, boolean flag) {
|
||||
if (root == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int left = robDown(root.left, !flag);
|
||||
int right = robDown(root.right, !flag);
|
||||
|
||||
if (flag) {
|
||||
return left + right + root.val;
|
||||
}else {
|
||||
return left + right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/11 11:14
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode343 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution().integerBreak(10));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* dp[i] 表示 拆分出i后的乘积的最大值
|
||||
* dp[i] = 遍历 dp[i-j] * i 或者 i * j
|
||||
* dp[i] 可能为两个数相乘,或者是多个数相乘(这时就需要遍历)。
|
||||
* 初始化 dp[0] = null;dp[1] = 1;
|
||||
*
|
||||
* [0 1 2 3 4 5 6 7 8 9 10]
|
||||
* [1 1 1 2 4 6 9 12 16 27 36]
|
||||
*
|
||||
*
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int integerBreak(int n) {
|
||||
|
||||
int[] dp = new int[n + 1];
|
||||
// dp[0] = 1;
|
||||
dp[2] = 1; // 表示数字2可以划分为1+1 1*1为最大值
|
||||
for (int i = 2; i < n+1; i++) {
|
||||
for (int j = 1; j < i - 1; j++) {
|
||||
// Math.max((i - j) * j, dp[i - j] * j) 表示两个数相乘 和使用 前面的数相乘
|
||||
dp[i] = Math.max(dp[i], Math.max((i - j) * j, dp[i - j] * j));
|
||||
}
|
||||
}
|
||||
|
||||
return dp[n];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/27 11:46
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode377 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1, 2, 3};
|
||||
int target = 4;
|
||||
int res = new Solution1().combinationSum4(nums, target);
|
||||
System.out.println(res);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 超时
|
||||
*/
|
||||
class Solution {
|
||||
int sum = 0;
|
||||
int res = 0;
|
||||
public int combinationSum4(int[] nums, int target) {
|
||||
backTracking(nums, target);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(int[] nums, int target) {
|
||||
if (sum == target) {
|
||||
res++;
|
||||
return;
|
||||
}
|
||||
if (sum > target) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
sum += nums[i];
|
||||
backTracking(nums, target);
|
||||
sum -= nums[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* dp 完全背包
|
||||
*/
|
||||
class Solution1 {
|
||||
|
||||
/**
|
||||
* 1 2 3随意取,使得总包围target
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int combinationSum4(int[] nums, int target) {
|
||||
|
||||
|
||||
// dp[j] 表示 从0-i-1任取,使得满足包容量为j的可能性
|
||||
/**
|
||||
* 0 1 2 3 4
|
||||
* [1, 1, 0, 0, 0]
|
||||
* [1, 1, 2, 0, 0]
|
||||
* [1, 1, 2, 4, 0]
|
||||
* [1, 1, 2, 4, 7]
|
||||
*/
|
||||
int[] dp = new int[target + 1];
|
||||
dp[0] = 1; // 都不放入 情况有一种
|
||||
for (int j = 1; j < target + 1; j++) {
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (j >= nums[i]) {
|
||||
dp[j] = dp[j] + dp[j - nums[i]];
|
||||
// dp[j] 不放
|
||||
// dp[j - nums[i]] 放,放也有多种情况
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 如果把遍历nums(物品)放在外循环,
|
||||
* 遍历target的作为内循环的话,举一个例子:
|
||||
* 计算dp[4]的时候,结果集只有 {1,3} 这样的集合,忽略了{3,1}
|
||||
*/
|
||||
}
|
||||
/**
|
||||
* 如果求 组合数 就是外层for循环遍历物品,内层for遍历背包。
|
||||
* 如果求 排列数 就是外层for遍历背包,内层for循环遍历物品。
|
||||
*/
|
||||
return dp[target];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/25 12:41
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode392 {
|
||||
@Test
|
||||
public void test() {
|
||||
String s = "abc";
|
||||
String t = "ahbgdc";
|
||||
boolean subsequence = new Solution1().isSubsequence(s, t);
|
||||
System.out.println(subsequence);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 子序列
|
||||
* s是否是t的子序列
|
||||
*
|
||||
* dp[i][j] 表示
|
||||
*
|
||||
* @param s
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public boolean isSubsequence(String s, String t) {
|
||||
|
||||
boolean flag = false;
|
||||
int j = 0;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
while (j < t.length()) {
|
||||
if (s.charAt(i) == t.charAt(j)) {
|
||||
flag = true;
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if (!flag) {
|
||||
return false;
|
||||
}
|
||||
flag = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* dp[i][j]表示s的i到t的j 相同子序列的长度
|
||||
*
|
||||
* 转变为 求两个序列相同子序列的长度
|
||||
*
|
||||
* ahbgdc
|
||||
* acbdc
|
||||
* @param s
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public boolean isSubsequence(String s, String t) {
|
||||
|
||||
int[][] dp = new int[s.length() + 1][t.length() + 1];
|
||||
char[] s1 = s.toCharArray();
|
||||
char[] t1 = t.toCharArray();
|
||||
for (int i = 1; i <= s1.length; i++) {
|
||||
for (int j = 1; j <= t1.length; j++) {
|
||||
if (s1[i - 1] == t1[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[s1.length][t1.length] == s1.length;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/14 12:24
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode416 {
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1,2,3,5};
|
||||
boolean canPartition = new Solution3().canPartition(nums);
|
||||
System.out.println(canPartition);
|
||||
}
|
||||
|
||||
// class Solution {
|
||||
// /**
|
||||
// * 分割为2部分
|
||||
// * @param nums
|
||||
// * @return
|
||||
// */
|
||||
// public boolean canPartition(int[] nums) {
|
||||
// Arrays.sort(nums);
|
||||
//
|
||||
// int rightSum = 0;
|
||||
// for (int num : nums) {
|
||||
// rightSum += num;
|
||||
// }
|
||||
// int leftSum = 0;
|
||||
// for (int i = 0; i < nums.length; i++) {
|
||||
// if (leftSum == rightSum) {
|
||||
// return true;
|
||||
// } else if (leftSum > rightSum) {
|
||||
// return false;
|
||||
// }
|
||||
// leftSum += nums[i];
|
||||
// rightSum -= nums[i];
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
class Solution {
|
||||
|
||||
int sumHalf = 0;
|
||||
int nowSum = 0;
|
||||
/**
|
||||
* 回溯
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public boolean canPartition(int[] nums) {
|
||||
for (int num : nums) {
|
||||
sumHalf += num;
|
||||
}
|
||||
sumHalf /= 2;
|
||||
return backTracking(nums, 0);
|
||||
}
|
||||
|
||||
public boolean backTracking(int[] nums, int start) {
|
||||
if (nowSum == sumHalf) {
|
||||
return true;
|
||||
}else if (nowSum>sumHalf){
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean b = false;
|
||||
for (int i = start; i < nums.length; i++) {
|
||||
nowSum += nums[i];
|
||||
b = backTracking(nums, i + 1);
|
||||
// 不行,有可能某些元素没在集合内
|
||||
nowSum -= nums[i];
|
||||
if (b==true) return true;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Solution2 {
|
||||
/**
|
||||
* 转换为背包问题
|
||||
* nums 为商品的重量、同时为商品的价值
|
||||
* 背包容量为sum/2 且需要装满
|
||||
*
|
||||
* 0 1 2 3 4 5
|
||||
* 0 0 n0 n0 n0 n0 n0
|
||||
* 1 0
|
||||
* 2 0
|
||||
* 3 0
|
||||
* 4 0
|
||||
* 5 0
|
||||
*
|
||||
* 不放东西的最大价值 dp[i][j] = dp[i-1][j]
|
||||
* 放东西的最大价值 max(dp[i-1][j] , dp[i-1][j-nums[i]]+values[i])
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public boolean canPartition(int[] nums) {
|
||||
int sumHalf = 0;
|
||||
for (int num : nums) {
|
||||
sumHalf += num;
|
||||
}
|
||||
if (sumHalf % 2 != 0) {
|
||||
return false;
|
||||
}
|
||||
sumHalf /= 2;
|
||||
|
||||
int length = nums.length;
|
||||
int[][] dp = new int[length][sumHalf + 1];
|
||||
// for (int i = 0; i < length; i++) {
|
||||
// dp[i][0] = 0;
|
||||
// }
|
||||
for (int i = nums[0]; i <= sumHalf; i++) {
|
||||
dp[0][i] = nums[0];
|
||||
}
|
||||
|
||||
for (int i = 1; i < length; i++) {
|
||||
for (int j = 1; j <= sumHalf; j++) {
|
||||
if (nums[i] > j) {
|
||||
// 放不下
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
} else {
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
|
||||
}
|
||||
|
||||
if (dp[i][j] == sumHalf) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution3 {
|
||||
/**
|
||||
* 将nums的元素放入背包中
|
||||
* 1. 背包容量 sum/2
|
||||
* 2. 物品i重量nums[i];价值nums[i]
|
||||
*
|
||||
* 0 1 2 3 4 5
|
||||
* 0
|
||||
* 1
|
||||
* 2
|
||||
*
|
||||
* dp[j]表示 j背包容量的最大价值
|
||||
*
|
||||
*
|
||||
*
|
||||
* // 递推公式
|
||||
* 2. 放下 dp[j] = max(dp[j], dp[j-weight[i]]+nums[i])
|
||||
*
|
||||
* 从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了。
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public boolean canPartition(int[] nums) {
|
||||
|
||||
int sum = 0;
|
||||
for (int num : nums) {
|
||||
sum += num;
|
||||
}
|
||||
|
||||
if (sum % 2 != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 包裹最大容量
|
||||
int packageCapacity = sum / 2;
|
||||
|
||||
int[] dp = new int[packageCapacity + 1];
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
// 包的容量必须大于物品i重量才能放进去
|
||||
/**
|
||||
* 如果正序遍历
|
||||
* dp[1] = dp[1 - weight[0]] + value[0] = 15
|
||||
* 此时容量1的背包已经放入了
|
||||
* dp[2] = dp[2 - weight[0]] + value[0] = 30
|
||||
* 此时又放入了一次
|
||||
*/
|
||||
for (int j = packageCapacity; j >= nums[i]; j--) {
|
||||
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
|
||||
//剪枝一下,每一次完成內層的for-loop,立即檢查是否dp[target] == target,優化時間複雜度(26ms -> 20ms)
|
||||
if(dp[packageCapacity] == packageCapacity)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 包裹容量和目标值一样
|
||||
return dp[packageCapacity] == packageCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/26 11:49
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode474 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
String[] strs = {"10","0001","111001","1","0"};
|
||||
int m = 5;
|
||||
int n = 3;
|
||||
// System.out.println(new Solution().findMaxForm(strs, m, n));
|
||||
// "10", "0", "1"
|
||||
strs = new String[]{"10","0","1"};
|
||||
System.out.println(new Solution1().findMaxForm(strs, 1, 1));
|
||||
|
||||
}
|
||||
class Solution {
|
||||
public int findMaxForm(String[] strs, int m, int n) {
|
||||
|
||||
// 三维 dp[i][j][k] 表示在前i个字符串中,包含了了j个0和k个1的最大子集长度
|
||||
// String[i]为物品 j k 为背包
|
||||
// 初始化: 当物品i=0 ,表示在前0个字符串中,没有字符串可以使用,dp[0][j][k]=0
|
||||
// 递推公式:
|
||||
// 获取0的数量numZero 获取1的数量numOne
|
||||
// 当j<numZero 或 k<numOne时,dp[i][j][k]=dp[i-1][j][k] 放不下
|
||||
// else
|
||||
// - 放 dp[i-1][j-numZero][k-numOne]+1
|
||||
// - 不放 dp[i-1][j][k]
|
||||
|
||||
int length = strs.length;
|
||||
int[][][] dp = new int[length + 1][m + 1][n + 1];
|
||||
for (int i = 1; i < strs.length + 1; i++) {
|
||||
String str = strs[i-1];
|
||||
int zeroNumber = calculateZeroNumber(str);
|
||||
int oneNumber = str.length() - zeroNumber;
|
||||
for (int j = 0; j <= m; j++) {
|
||||
for (int k = 0; k <= n; k++) {
|
||||
if (j < zeroNumber || k < oneNumber) {
|
||||
dp[i][j][k] = dp[i - 1][j][k];
|
||||
} else {
|
||||
dp[i][j][k] = Math.max(dp[i - 1][j - zeroNumber][k - oneNumber] + 1, dp[i - 1][j][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[length][m][n];
|
||||
}
|
||||
|
||||
public int calculateZeroNumber(String str)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (str.charAt(i) == '0')
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public int findMaxForm(String[] strs, int m, int n) {
|
||||
|
||||
// 二维dp dp[j][k] 表示 从字符串[1-i]中取字符串放入 0背包容量为j 1背包容量为k 的最大子串长度
|
||||
//
|
||||
// 递推公式
|
||||
// 遍历每个字符串,获取0个数为zeroNumber 1 个数为oneNumber
|
||||
// dp[j][k] =
|
||||
// - 放 dp[j-zero][k-one]+1
|
||||
// - 不放 dp[j][k]
|
||||
// 遍历 背包
|
||||
// - 从后往前 确保背包容量j能够放下oneNumber 即j>=zeroNumber
|
||||
int[][] dp = new int[m + 1][n + 1];
|
||||
|
||||
for (String str : strs) {
|
||||
int zeroNumber = calculateZeroNumber(str);
|
||||
int oneNumber = str.length() - zeroNumber;
|
||||
for (int j = m; j >= zeroNumber; j--) {
|
||||
for (int k = n; k >= oneNumber; k--) {
|
||||
dp[j][k] = Math.max(dp[j - zeroNumber][k - oneNumber] + 1, dp[j][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[m][n];
|
||||
}
|
||||
|
||||
public int calculateZeroNumber(String str)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (str.charAt(i) == '0')
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/18 16:17
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode494 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums = {1,1,1,1,1};
|
||||
int target = 3;
|
||||
System.out.println(new Solution2().findTargetSumWays(nums, target));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 背包容量为3
|
||||
* left(+1的数量)-right(-1的数量) = target
|
||||
* left-right = target
|
||||
* left+right = sum (right = sum -left)
|
||||
* left = (target + sum)/2
|
||||
* 表示正数有多少个是固定的,就是我们的背包容量
|
||||
*
|
||||
*
|
||||
* 使用nums[i] 里面全是1 装满容量为left的背包,有几种方法
|
||||
*
|
||||
* if j> nums[i]
|
||||
* dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]
|
||||
* 不放 放
|
||||
* else
|
||||
* dp[i][j] = dp[i-1][j]
|
||||
* 1,1,1,1,1
|
||||
*
|
||||
* 0 1 2 3 4
|
||||
* 0 1 1 0 0 0
|
||||
* 1 0 0 1 0 0
|
||||
* 2 0 3
|
||||
* 3
|
||||
* 4
|
||||
*
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int findTargetSumWays(int[] nums, int target) {
|
||||
|
||||
int sum = 0;
|
||||
for (int num : nums) {
|
||||
sum += num;
|
||||
}
|
||||
|
||||
// 总和还比不过绝对值,1不够用
|
||||
if(sum < Math.abs(target)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// left 为+1的数量 +1的数量必须是整数
|
||||
if((sum + target) % 2 != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int left = (sum + target) >> 1; // (sum + target) / 2;
|
||||
|
||||
|
||||
int length = nums.length;
|
||||
int[][] dp = new int[length + 1][left + 1];
|
||||
|
||||
|
||||
// 01背包
|
||||
// i(1 ~ len)表示遍历(不一定选)了 i 个元素,j(0 ~ sum) 表示它们的和
|
||||
dp[0][0] = 1;
|
||||
for (int i = 1; i <= length; i++) {
|
||||
for (int j = 0; j <= left; j++) {
|
||||
// 装不下(不选当前元素)
|
||||
if (j - nums[i - 1] < 0) {
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
// 可装可不装(当前元素可选可不选)
|
||||
} else {
|
||||
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:0个元素,和为0,情况有1种(因为没有元素,所以只能不选,和为0):dp[0][0] = 1
|
||||
* 不选当前元素,即"部分和"(即j)与之前相同:dp[i][j] = dp[i - 1][j]
|
||||
* 可选可不选,不选的情况是2,选当前元素的话则之前的状态应为dp[i - 1][j - num](这里的num指的是当前元素的值,即代码中的nums[i - 1]),二者相加,即:dp[i][j] = dp[i - 1][j] + dp[i - 1][j - num]
|
||||
*/
|
||||
|
||||
return dp[length][left];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
|
||||
public int findTargetSumWays(int[] nums, int S) {
|
||||
int sum = 0;
|
||||
for (int num : nums) {
|
||||
sum += num;
|
||||
}
|
||||
// 背包容量为整数,sum + S为奇数的话不满足要求
|
||||
if (((sum + S) & 1) == 1) {
|
||||
return 0;
|
||||
}
|
||||
// 目标和不可能大于总和
|
||||
if (S > sum) {
|
||||
return 0;
|
||||
}
|
||||
sum = (sum + S) >> 1;
|
||||
int len = nums.length;
|
||||
int[][] dp = new int[len + 1][sum + 1];
|
||||
dp[0][0] = 1;
|
||||
|
||||
// 如果迭代部分 j 的初值赋 1 的话,就要先初始化 j = 0 的情况
|
||||
/* int count = 1;
|
||||
for (int i = 1; i <= len; i++) {
|
||||
// ±0 均可
|
||||
if (nums[i - 1] == 0) {
|
||||
count *= 2;
|
||||
}
|
||||
dp[i][0] = count;
|
||||
} */
|
||||
|
||||
// 01背包
|
||||
// i(1 ~ len)表示遍历(不一定选)了 i 个元素,j(0 ~ sum) 表示它们的和
|
||||
for (int i = 1; i <= len; i++) {
|
||||
for (int j = 0; j <= sum; j++) {
|
||||
// 装不下(不选当前元素)
|
||||
if (j - nums[i - 1] < 0) {
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
// 可装可不装(当前元素可选可不选)
|
||||
} else {
|
||||
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[len][sum];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Solution2 {
|
||||
public int findTargetSumWays(int[] nums, int S) {
|
||||
int sum = 0;
|
||||
for(int i=0; i<nums.length; i++){
|
||||
sum += nums[i];
|
||||
nums[i] += nums[i];
|
||||
}
|
||||
if(S>sum) return 0;
|
||||
S += sum;
|
||||
int[] dp = new int[S+1];
|
||||
dp[0] = 1;
|
||||
for(int num: nums){
|
||||
for(int i=S; i>=0; i--){
|
||||
if(i-num>=0){
|
||||
dp[i] = dp[i] + dp[i-num];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[S];
|
||||
}
|
||||
}
|
||||
|
||||
class Solution3 {
|
||||
/**
|
||||
* 查找目标和的方法数
|
||||
* 给定一个整数数组 nums 和一个目标整数 target,求出可以通过从数组中选择数字并进行加法运算得到目标和的方法数。
|
||||
* 数组中的每个数字可以被选择任意次数。
|
||||
*
|
||||
* 其中 dp[i][j] 表示在数组 nnums 的前 i 个数中选取元素,使得这些元素之和等于 j 的方案数
|
||||
*
|
||||
*
|
||||
* @param nums 整数数组,包含要进行加法运算的整数
|
||||
* @param target 目标整数,要达到的和
|
||||
* @return 返回可以通过选择数组中的数字并进行加法运算得到目标和的方法数
|
||||
*/
|
||||
public int findTargetSumWays(int[] nums, int target) {
|
||||
// 计算数组 nums 中所有数字的和
|
||||
int sum = 0;
|
||||
for (int num : nums) {
|
||||
sum += num;
|
||||
}
|
||||
// 计算达到目标和需要减去的数
|
||||
int diff = sum - target;
|
||||
// 如果差值小于0或者差值为奇数,则无法达到目标和,返回0
|
||||
if (diff < 0 || diff % 2 != 0) {
|
||||
return 0;
|
||||
}
|
||||
// 计算可以取的负数的个数
|
||||
int n = nums.length;
|
||||
int neg = diff / 2;
|
||||
// 使用动态规划的二维数组,dp[i][j] 表示前 i 个数字中选取和为 j 的方法数
|
||||
int[][] dp = new int[n + 1][neg + 1];
|
||||
// 初始化,当不选取任何数字时,和为 0 的方法数为 1
|
||||
dp[0][0] = 1;
|
||||
// 遍历数组 nums,更新 dp 数组
|
||||
for (int i = 1; i <= n; i++) {
|
||||
int num = nums[i - 1];
|
||||
for (int j = 0; j <= neg; j++) {
|
||||
// 不选择当前数字 num
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
// 选择当前数字 num
|
||||
if (j >= num) {
|
||||
dp[i][j] += dp[i - 1][j - num];
|
||||
}
|
||||
}
|
||||
}
|
||||
// 返回最后一个数字选取和为 neg 的方法数
|
||||
return dp[n][neg];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test1()
|
||||
{
|
||||
int[] nums = {1,1,1,1,1};
|
||||
int target = 3;
|
||||
System.out.println(new Solution3().findTargetSumWays(nums, target));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/8 11:44
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode509 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution1().fib(10));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int fib(int n) {
|
||||
if (n==0) return 0;
|
||||
if (n==1) return 1;
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* 1. 确定dp数组(dp table)以及下标的含义
|
||||
* 2. 确定递推公式 dp[i] = dp[i - 1] + dp[i - 2];
|
||||
* 3. dp数组如何初始化 dp[0] = 0; dp[1] = 1;
|
||||
* 4. 确定遍历顺序
|
||||
* 5. 举例推导dp数组 0 1 1 2 3 5 8 13 21 34 55
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int fib(int n) {
|
||||
if (n<=1) return n;
|
||||
int[] dp = new int[n + 1];
|
||||
dp[0] = 0;
|
||||
dp[1] = 1;
|
||||
for (int i = 2; i <= n; i++) {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/5/2 15:57
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode516 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
Solution solution = new Solution();
|
||||
System.out.println(solution.longestPalindromeSubseq("bbbab"));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 子序列
|
||||
* dp[i][j] 表示 i-j的最长回文子序列长度
|
||||
* 0 1 2 3 4
|
||||
* 0 1
|
||||
* 1 2 1
|
||||
* 2 3 2 1
|
||||
* 3 3 2 1 1 不相等取上、右边的最大值
|
||||
* 4 4 3 3 1 1 相等 取dp[i+1][j-1]+2
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public int longestPalindromeSubseq(String s) {
|
||||
int[][] dp = new int[s.length()][s.length()];
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
for (int j = i; j >= 0; j--) {
|
||||
if (i == j) {
|
||||
dp[i][j] = 1;
|
||||
continue;
|
||||
}
|
||||
if (s.charAt(i) == s.charAt(j)) {
|
||||
dp[i][j]= dp[i - 1][j + 1] + 2;
|
||||
}else {
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[s.length() - 1][0];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/26 15:37
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode518 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] coins = {1, 2, 5};
|
||||
int amount = 5;
|
||||
int i = new Solution2().change(amount, coins);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* dp[j] 表示前i个硬币容量为j的背包能够装入的组合数
|
||||
*
|
||||
* dp[j] = dp[j-coins[i-1]] + 1
|
||||
*
|
||||
* @param amount
|
||||
* @param coins
|
||||
* @return
|
||||
*/
|
||||
public int change(int amount, int[] coins) {
|
||||
|
||||
|
||||
int[] dp = new int[amount + 1];
|
||||
|
||||
dp[0] = 1;
|
||||
for (int i = 1; i <= coins.length; i++) {
|
||||
for (int j = coins[i - 1]; j <= amount; j++) {
|
||||
dp[j] = dp[j] + dp[j - coins[i - 1]] ;
|
||||
}
|
||||
}
|
||||
|
||||
return dp[amount];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Solution2{
|
||||
|
||||
/**
|
||||
* 二维数组
|
||||
* @param amount
|
||||
* @param coins
|
||||
* @return
|
||||
*/
|
||||
public int change(int amount, int[] coins) {
|
||||
int n = coins.length;
|
||||
int[][] dp = new int[n + 1][amount + 1];
|
||||
|
||||
// 初始化第一行,即不使用任何硬币时,只有金额为0的方法数为1
|
||||
for (int j = 0; j <= amount; j++) {
|
||||
dp[0][j] = 0;
|
||||
}
|
||||
dp[0][0] = 1;
|
||||
|
||||
// 初始化第一列,即凑齐金额为0的方法数都是1(不使用任何硬币)
|
||||
for (int i = 0; i <= n; i++) {
|
||||
dp[i][0] = 1;
|
||||
}
|
||||
|
||||
// 动态规划填表
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= amount; j++) {
|
||||
// 不使用第i种硬币
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
|
||||
// 如果当前金额j大于等于第i种硬币的面值,那么可以考虑使用这种硬币
|
||||
// 使用第i种硬币的方法数等于不使用第i种硬币的方法数加上使用第i种硬币后的方法数
|
||||
if (j >= coins[i - 1]) {
|
||||
dp[i][j] += dp[i][j - coins[i - 1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[n][amount];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/25 11:59
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode53 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Solution solution = new Solution();
|
||||
int[] nums = new int[]{-1,-3};
|
||||
int i = solution.maxSubArray(nums);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int maxSubArray(int[] nums) {
|
||||
// dp[i] 表示包含元素i的的最大和
|
||||
// dp[0] = nums[0]
|
||||
|
||||
int[] dp = new int[nums.length];
|
||||
dp[0] = nums[0];
|
||||
int max = nums[0];
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
if (dp[i - 1] > 0 && dp[i - 1] + nums[i] > 0) { // 如果p[i - 1] < 0 则只能拖后腿
|
||||
dp[i] = dp[i - 1] + nums[i];
|
||||
} else {
|
||||
// 拖后腿,重新计算
|
||||
dp[i] = nums[i];
|
||||
}
|
||||
max = Math.max(max, dp[i]);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/5/2 11:14
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode583 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
|
||||
// "leetcode", word2 = "etco"
|
||||
int i = new Solution1().minDistance("leetcode", "etco");
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 最长子序列的长度
|
||||
* word1.len - dp
|
||||
* word2.len - dp
|
||||
* @param word1
|
||||
* @param word2
|
||||
* @return
|
||||
*/
|
||||
public int minDistance(String word1, String word2) {
|
||||
/**
|
||||
* dp[i][j] 表示 word1的0-i word2的0-j 最长公共子序列的长度
|
||||
*
|
||||
* '' s e a
|
||||
* '' 0 0 0 0
|
||||
* e 0 0 1 1
|
||||
* a 0 0 1 2
|
||||
* t 0 0 1 2
|
||||
*
|
||||
*/
|
||||
|
||||
int len2 = word2.length();
|
||||
int len1 = word1.length();
|
||||
int[][] dp = new int[len1 + 1][len2 + 1];
|
||||
|
||||
for (int i = 1; i <= len1; i++) {
|
||||
for (int j = 1; j <= len2; j++) {
|
||||
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return len1 + len2 - (dp[len1][len2] << 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
|
||||
* '' s e a
|
||||
* '' 0 1 2 3
|
||||
* e 1 2 1 2
|
||||
* a 2 3 2 1
|
||||
* t 3 4 3 2
|
||||
* 等 dp[i-1][j-1]
|
||||
* 不等 min(dp[i-1][j], dp[i][j-1]) + 1
|
||||
* 1. 删word1[i - 1],最少操作次数为dp[i - 1][j] + 1
|
||||
* 2. 删word2[j - 1],最少操作次数为dp[i][j - 1] + 1
|
||||
* 3. 同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2
|
||||
* dp[i][j - 1] + 1 = dp[i - 1][j - 1] + 2
|
||||
* @param word1
|
||||
* @param word2
|
||||
* @return
|
||||
*/
|
||||
public int minDistance(String word1, String word2) {
|
||||
int len2 = word2.length();
|
||||
int len1 = word1.length();
|
||||
int[][] dp = new int[len1 + 1][len2 + 1];
|
||||
|
||||
for (int i = 1; i <= len1; i++) {
|
||||
dp[i][0] = i;
|
||||
}
|
||||
for (int j = 1; j <= len2; j++) {
|
||||
dp[0][j] = j;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= len1; i++) {
|
||||
for (int j = 1; j <= len2; j++) {
|
||||
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
} else {
|
||||
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[len1][len2];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* TODO 还没写完
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/8 12:58
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode62 {
|
||||
|
||||
@Test
|
||||
public void test(
|
||||
) {
|
||||
System.out.println(new Solution().uniquePaths(3, 3));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 确定dp[i,j] 该点可能的路径数
|
||||
* 递推公式 dp[i,j]= dp[i-1,j] + dp[i,j-1]
|
||||
* 初始化 dp[0,0]=1
|
||||
* 推
|
||||
* 0 1 1 1 1 1 1
|
||||
* 1 2 3 4 5 6 7
|
||||
* 1 3 6 10 15 21 28
|
||||
* @param m
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int uniquePaths(int m, int n) {
|
||||
int[][] dp = new int[m][n];
|
||||
dp[0][0] = 1;
|
||||
for (int i = 0; i < m; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (i>=1) dp[i][j] += dp[i - 1][j];
|
||||
if (j>=1) dp[i][j] += dp[i][j - 1];
|
||||
}
|
||||
}
|
||||
return dp[m - 1][n - 1];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/9 12:04
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode63 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] ints = new int[][]{{0,0,0,0},{0,1,0,0},{0,0,0,0}};
|
||||
System.out.println(new Solution().uniquePathsWithObstacles(ints));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* dp[i][j] 表示 i,j出可能的路径
|
||||
* dp[i][j] = dp[i-1][j] + dp[i][j-1] 且如果该点有障碍,直接continue
|
||||
* 初始化 dp【0,0】=0
|
||||
* @param obstacleGrid
|
||||
* @return
|
||||
*/
|
||||
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
|
||||
|
||||
if (obstacleGrid[0][0] == 1) {
|
||||
return 0;//起点就有障碍,不可能过去
|
||||
}
|
||||
|
||||
int h = obstacleGrid.length;
|
||||
int w = obstacleGrid[0].length;
|
||||
int[][] dp = new int[h][w];
|
||||
dp[0][0] = 1;
|
||||
for (int i = 0; i < dp.length; i++) {
|
||||
for (int j = 0; j < dp[i].length; j++) {
|
||||
if (i == 0 && j == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obstacleGrid[i][j] == 0) {
|
||||
int tmp = 0;
|
||||
if (i >= 1) tmp += dp[i - 1][j];
|
||||
if (j >= 1) tmp += dp[i][j - 1];
|
||||
dp[i][j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[h-1][w-1];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/16 11:22
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode64 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[][] grid = new int[][] { {1,2,3}, {4,5,6} };
|
||||
Solution solution = new Solution();
|
||||
int i = solution.minPathSum(grid);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* dp
|
||||
* int[i][j]表示到该点所需的最最小数字总和
|
||||
*
|
||||
* @param grid
|
||||
* @return
|
||||
*/
|
||||
public int minPathSum(int[][] grid) {
|
||||
|
||||
int h = grid.length;
|
||||
int w = grid[0].length;
|
||||
int[][] dp = new int[h][w];
|
||||
dp[0][0] = grid[0][0];
|
||||
|
||||
// dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j]
|
||||
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = 0; j < w; j++) {
|
||||
if (i == 0 && j == 0) {
|
||||
continue;
|
||||
}
|
||||
if (j == 0 && i != 0) {
|
||||
dp[i][j] = dp[i - 1][j] + grid[i][j];
|
||||
continue;
|
||||
}
|
||||
if (i == 0 && j != 0) {
|
||||
dp[i][j] = dp[i][j - 1] + grid[i][j];
|
||||
continue;
|
||||
}
|
||||
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
|
||||
}
|
||||
}
|
||||
return dp[h - 1][w - 1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/22 12:36
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode647 {
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 判断一个子字符串(字符串的下表范围[i,j])是否回文,
|
||||
* 依赖于子字符串(下表范围[i + 1, j - 1])) 是否是回文。
|
||||
*
|
||||
* 布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串
|
||||
*
|
||||
* ij两个循环,能够覆盖所有循环
|
||||
* - dp[i][j] 判断是否回文的时候,只需要dp[i+1][j-1]是否回文,并且s[i]==s[j]
|
||||
* 当s[i]=s[j]
|
||||
* 1. i=j 回文
|
||||
* 2. i+1=j 回文
|
||||
* 3. dp[i+1][j-1]==true 回文
|
||||
*
|
||||
*
|
||||
* <img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20210121171032473-20230310132134822.jpg" alt="">
|
||||
* dp[i][j]由dp[i+1][j-1]过来,所以必须从下到上,左到右
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public int countSubstrings(String s) {
|
||||
|
||||
char[] chars = s.toCharArray();
|
||||
|
||||
boolean[][] dp = new boolean[chars.length][chars.length];
|
||||
int res = 0;
|
||||
for (int i = s.length() - 1; i >= 0; i--) {
|
||||
for (int j = i; j < s.length(); j++) {
|
||||
if (chars[i] == chars[j]) {
|
||||
if (j - i == 1|| i==j || dp[i + 1][j - 1]) {
|
||||
dp[i][j] = true;
|
||||
res++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Solution1 {
|
||||
public int countSubstrings(String s) {
|
||||
// 中心点向外扩充
|
||||
// 1个元素可以作为中心点
|
||||
// 2个元素也能作为中心点
|
||||
char[] chars = s.toCharArray();
|
||||
int res = 0;
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
res += subString(chars, i, i);
|
||||
res += subString(chars, i, i + 1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chars
|
||||
* @param center1 向左扩展的指针
|
||||
* @param center2 向右扩展的指针
|
||||
* @return 有几个子串
|
||||
*/
|
||||
public int subString(char[] chars, int center1, int center2) {
|
||||
int res = 0;
|
||||
while (center1 >= 0 && center2 < chars.length && chars[center1] == chars[center2]) {
|
||||
center1--;
|
||||
center2++;
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
Solution1 solution = new Solution1();
|
||||
String s = "aaa";
|
||||
int res = solution.countSubstrings(s);
|
||||
System.out.println(res);
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/5/2 12:00
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode647_1 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
String s = "abc";
|
||||
System.out.println(new Solution().countSubstrings(s));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
*
|
||||
* 给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目
|
||||
*
|
||||
* dp[i][j] 表示 i-j回文字符串的数量
|
||||
*
|
||||
* dp[i][j] 由 dp[i+1][j-1]推出
|
||||
* if n[i]==n[j]
|
||||
* dp[i][j] = dp[i-1][j-1]+2
|
||||
* else
|
||||
* dp[i][j] = dp[i][j-1]+dp[i+1][j]
|
||||
*
|
||||
* abac
|
||||
* '' 0 1 2 3
|
||||
* '' 0 0 0 0 0
|
||||
* 0 0 1
|
||||
* 1 0 0 1
|
||||
* 2 0 1 0 1
|
||||
* 3 0 0 0 0 1
|
||||
*
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public int countSubstrings(String s) {
|
||||
boolean[][] dp = new boolean[s.length()][s.length()];
|
||||
int res = 0;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
for (int j = i; j >= 0; j--) {
|
||||
if (i == j ) {
|
||||
dp[i][j] = true;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if ((s.charAt(i) == s.charAt(j)) && (i == j + 1 || dp[i - 1][j + 1])) {
|
||||
dp[i][j] = true;
|
||||
res++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/23 11:56
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode674 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
|
||||
int[] nums = new int[]{1,1,1,1};
|
||||
int lengthOfLCIS = new Solution1().findLengthOfLCIS(nums);
|
||||
System.out.println(lengthOfLCIS);
|
||||
}
|
||||
|
||||
class Solution2 {
|
||||
/**
|
||||
* 如果当前元素大于前一个元素,则递增计数,并将计数与结果中的最大值进行比较更新。
|
||||
* 如果当前元素不大于前一个元素,则将计数重置为1。
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int findLengthOfLCIS(int[] nums) {
|
||||
int res = 1;
|
||||
int count = 1;
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
if (nums[i] > nums[i - 1]) {
|
||||
count++;
|
||||
res = Math.max(res, count);
|
||||
} else {
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
|
||||
/**
|
||||
* 最长且 连续递增的子序列
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int findLengthOfLCIS(int[] nums) {
|
||||
// 找到所有递增区间
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
int maxLength = 0;
|
||||
while (right < nums.length - 1) {
|
||||
if (nums[right + 1] <= nums[right]) {
|
||||
maxLength = Math.max(maxLength, right - left + 1);
|
||||
right++;
|
||||
left = right;
|
||||
}else {
|
||||
right++;
|
||||
}
|
||||
}
|
||||
|
||||
return Math.max(maxLength, right - left + 1);
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public int findLengthOfLCIS(int[] nums) {
|
||||
/**
|
||||
* dp[i] 表示可包含i的最长子序列长度
|
||||
* if nums[i] > nums[i-1] 递增
|
||||
* dp[i] = dp[i-1]+1
|
||||
* else
|
||||
* dp[i] = 1 一旦出现递减,因为前面的连续递增是不能用的,需要直接重置
|
||||
*/
|
||||
int[] dp = new int[nums.length];
|
||||
dp[0] = 1;
|
||||
int ans = 1;
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
if (nums[i] > nums[i-1]) {
|
||||
dp[i] = dp[i-1] + 1;
|
||||
}else {
|
||||
dp[i] = 1;
|
||||
}
|
||||
ans = Math.max(ans, dp[i]);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/8 12:11
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode70 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution().climbStairs(0));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 1. 确定dp数组含义 dp[i] 表示到这里的方法数
|
||||
* 2. 地推公式 dp[i] = dp[i-1]+dp[i-2]
|
||||
* 3. 初始化 dp[0] = 1;dp[1]=1
|
||||
* 4. 模拟推导1 1 2 3 5 8
|
||||
* 0 1 2 3 4 5
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int climbStairs(int n) {
|
||||
if (n <= 1) {
|
||||
return n;
|
||||
}
|
||||
int[] dp = new int[n];
|
||||
dp[0] = 1;
|
||||
dp[1] = 2;
|
||||
for (int i = 2; i < n; i++) {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
}
|
||||
return dp[n-1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/19 12:27
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode714 {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] prices = {1, 3, 2, 8, 4, 9};
|
||||
int maxProfit = new Solution1().maxProfit(prices, 2);
|
||||
System.out.println(maxProfit);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* dp[i][0] 表示手里没有股票的最大手头持有
|
||||
* - i-1 就没有 dp[i-1][0]
|
||||
* - i刚刚卖出 dp[i-1][1] + price[i] - fee
|
||||
* dp[i][1] 表示手里有股票的最大手头持有
|
||||
* - i-1 有 dp[i-1][1]
|
||||
* - i刚刚买入 dp[i-1][0] - price[i] - fee
|
||||
* @param prices
|
||||
* @param fee
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices, int fee) {
|
||||
int[][] dp = new int[prices.length][2];
|
||||
dp[0][1] = -prices[0] - fee;
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i] - fee);
|
||||
}
|
||||
return dp[prices.length - 1][0];
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* dp[i][0] 表示手里没有股票的最大手头持有
|
||||
* - i-1 就没有 dp[i-1][0]
|
||||
* - i刚刚卖出 dp[i-1][1] + price[i] - fee
|
||||
* dp[i][1] 表示手里有股票的最大手头持有
|
||||
* - i-1 有 dp[i-1][1]
|
||||
* - i刚刚买入 dp[i-1][0] - price[i] - fee
|
||||
* @param prices
|
||||
* @param fee
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices, int fee) {
|
||||
int[] dp = new int[2];
|
||||
dp[1] = -prices[0] - fee;
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[0] = Math.max(dp[0], dp[1] + prices[i]);
|
||||
dp[1] = Math.max(dp[1], dp[0] - prices[i] - fee);
|
||||
}
|
||||
return dp[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/23 12:22
|
||||
* @注释
|
||||
*/
|
||||
|
||||
public class LeetCode718 {
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
int[] nums1 = {1,2,3,2,1};
|
||||
int[] nums2 = {3,2,1,4,7};
|
||||
|
||||
int i = new Solution1().findLength(nums1, nums2);
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int findLength(int[] nums1, int[] nums2) {
|
||||
|
||||
/**
|
||||
* 用二维数组可以记录两个字符串的所有比较情况
|
||||
* dp[i][j] 表示 以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度
|
||||
* dp[i][j] 可以由dp[i-1][j-1] + 1 和 0 两种情况推出
|
||||
*
|
||||
* dp[i][j]
|
||||
* if nums1[i]==nums[j]
|
||||
* dp[i][j] = dp[i-1][j-1] + 1
|
||||
* else
|
||||
* dp[i][j] = 0
|
||||
*/
|
||||
int[][] dp = new int[nums1.length + 1][nums2.length + 1];
|
||||
int res = 0;
|
||||
for (int i = 1; i <= nums1.length; i++) {
|
||||
for (int j = 1; j <= nums2.length; j++) {
|
||||
if (nums1[i - 1] == nums2[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
dp[i][j] = 0;
|
||||
}
|
||||
res = Math.max(res, dp[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
public int findLength(int[] nums1, int[] nums2) {
|
||||
|
||||
/**
|
||||
* dp[i][j]都是由dp[i - 1][j - 1]推出。那么压缩为一维数组,也就是dp[j]都是由dp[j - 1]推出。
|
||||
*
|
||||
*/
|
||||
int[] dp = new int[nums1.length + 1];
|
||||
int res = 0;
|
||||
for (int i = 1; i <= nums1.length; i++) {
|
||||
for (int j = nums2.length; j > 0; j--) { // 从后面开始比较,避免重复覆盖dp[i]
|
||||
if (nums1[i - 1] == nums2[j - 1]) {
|
||||
dp[j] = dp[j - 1] + 1;
|
||||
} else {
|
||||
dp[j] = 0;
|
||||
}
|
||||
res = Math.max(res, dp[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/8 12:24
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode746 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution().minCostClimbingStairs(new int[]{1,1001}));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
* 含义 dp[i] 走到这最少支出的花费
|
||||
* 递推公式
|
||||
* dp[i] = min{dp[i-2]+cost[i-2] , dp[i-1]+cost[i-1]}
|
||||
* 初始化 dp[0]=0 dp[1]=0
|
||||
* 模拟推导
|
||||
* 1,100,1,1,1,100,1,1,100,1
|
||||
* 0 0 1 2
|
||||
*
|
||||
* @param cost
|
||||
* @return
|
||||
*/
|
||||
public int minCostClimbingStairs(int[] cost) {
|
||||
//一旦你支付此费用,即可选择向上爬一个或者两个台阶。
|
||||
int length = cost.length;
|
||||
int[] dp = new int[length+1];
|
||||
dp[0] = 0;
|
||||
dp[1] = 0;
|
||||
|
||||
for (int i = 2; i <= length; i++) {
|
||||
// 前面两个数有可能跳到本数,判断前两个数跳本数的代价
|
||||
dp[i] = Math.min(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1]);
|
||||
}
|
||||
return dp[length];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/3/11 13:08
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode96 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int n = 5;
|
||||
int result = new Solution().numTrees(n);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
*
|
||||
* dp[i] 表示有两个节点的可能数
|
||||
*
|
||||
* 以n=3举例,二叉搜索树
|
||||
* 可能的方案:
|
||||
* i表示以i为头节点
|
||||
* 1. 以1为头结点 右边2个子树+左边0个子树
|
||||
* 2. 以2为头节点 右边1个子树+左边1个子树
|
||||
* 3. 以3为头节点 右边0个子树+左边2个子树
|
||||
*
|
||||
* dp[3] = 以1为头 dp[2] * dp[0] +
|
||||
* 以2为头 dp[1] * dp[1] +
|
||||
* 以3为头 dp[0] * dp[2]
|
||||
*
|
||||
* dp[i] = dp[i-1] * dp[0] +
|
||||
* dp[i-2] * dp[1] +
|
||||
* dp[i-3] * dp[02] +
|
||||
* ....
|
||||
* dp[0] * dp[i-1]
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int numTrees(int n) {
|
||||
|
||||
if (n <= 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int[] dp = new int[n + 1];
|
||||
dp[0] = 1;
|
||||
dp[1] = 1;
|
||||
dp[2] = 2;
|
||||
for (int i = 3; i <= n; i++) {
|
||||
for (int j = 1; j <= i; j++) {
|
||||
dp[i] += (dp[i - j] * dp[j - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return dp[n];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,349 +0,0 @@
|
||||
package cn.whaifree.leetCode.Dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* 买卖股票的最佳时机 四题+变形
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/4/12 11:46
|
||||
* @注释
|
||||
*/
|
||||
public class Stock {
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
System.out.println(new LeetCode188_.Solution().maxProfit(2, new int[]{3,2,6,5,0,3}));
|
||||
}
|
||||
}
|
||||
|
||||
class LeetCode188_{
|
||||
|
||||
static class Solution {
|
||||
public int maxProfit(int k, int[] prices) {
|
||||
// dp[i][j] 表示第i天交易第k次的最大收益
|
||||
// dp[i][1] 表示第i天第 1/2 +1 次持有的最大手头
|
||||
// dp[i][0] 表示第i天第 0/2 +1次未持有的最大手头
|
||||
|
||||
// dp[i][0] = max dp[i-1][0] dp[i-1][1]+prices[i]
|
||||
// dp[i][1] = max dp[i-1][1] dp[i-1][0]-prices[i]
|
||||
// dp[i][2] = max dp[i-1][2] dp[i-1][1]+prices[i]
|
||||
// dp[i][3] = max dp[i-1][3] dp[i-1][2]-prices[i]
|
||||
|
||||
int[][] dp = new int[prices.length][k * 2 + 1];
|
||||
// 未持有 初始化
|
||||
for (int i = 1; i <= k * 2; i += 2) {
|
||||
dp[0][i] = -prices[0];
|
||||
}
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
for (int j = 0; j < k ; j++) {
|
||||
int indexJ = 2 * j + 1;
|
||||
dp[i][indexJ] = Math.max(dp[i - 1][indexJ], dp[i - 1][indexJ - 1] - prices[i]);
|
||||
dp[i][indexJ + 1] = Math.max(dp[i - 1][indexJ + 1], dp[i - 1][indexJ] + prices[i]);
|
||||
}
|
||||
}
|
||||
return dp[prices.length - 1][k * 2];
|
||||
|
||||
// 假设k=2
|
||||
// int[][] dp = new int[prices.length][5];
|
||||
// // 4种状态 1 3 表示持有
|
||||
// dp[0][1] = -prices[0];
|
||||
// dp[0][3] = -prices[0];
|
||||
// for (int i = 1; i < prices.length; i++) {
|
||||
// dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
|
||||
// dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
|
||||
// dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
|
||||
// dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
|
||||
// }
|
||||
// return dp[prices.length - 1][4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LeetCode123_ {
|
||||
|
||||
static class Solution {
|
||||
/**
|
||||
* 最多可以完成 两笔 交易。
|
||||
* 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
|
||||
*
|
||||
* dp[i][j] 表示第i天 状态j的最大手头有的钱
|
||||
* 一天一共就有五个状态,
|
||||
* 0. 没有操作 (其实我们也可以不设置这个状态)
|
||||
*
|
||||
* 1. 第一次持有股票(第i天持有第一次股票)
|
||||
* - 第i-1天就持有这个第一次股票 dp[i][1] = dp[i-1][1]
|
||||
* - 第i天买入这个股票 dp[i][1] = dp[i-1][0] - prices[i]
|
||||
* 2. 第一次不持有股票
|
||||
* - 第i天卖出 dp[i][2] = dp[i-1][1]+price[i]
|
||||
* - 第i-1天就不持有第一支 dp[i][2] = dp[i-1][2]
|
||||
* 3. 第二次持有股票
|
||||
* - 第i天买入第二支 dp[i][3] = dp[i-1][2] - price[i]
|
||||
* - i-1天就持有 dp[i][3] = dp[i-1][3]
|
||||
* 4. 第二次不持有股票
|
||||
* - 第i天卖出第二支 dp[i][4] = dp[i-1][3] + price[i]
|
||||
* - 第i-1天就没有 dp[i][4] = dp[i-1][4]
|
||||
*
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices) {
|
||||
int[][] dp = new int[prices.length][5];
|
||||
dp[0][1] = -prices[0];
|
||||
dp[0][3] = -prices[0];
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
// 没有操作,手上的现金自然就是0
|
||||
// dp[i][1] = Math.max(dp[i - 1][1], 0 - prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
|
||||
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
|
||||
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
|
||||
dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
|
||||
}
|
||||
return dp[prices.length - 1][4];
|
||||
}
|
||||
|
||||
public int maxProfit1(int[] prices) {
|
||||
int[] dp = new int[5];
|
||||
dp[1] = -prices[0];
|
||||
dp[3] = -prices[0];
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[1] = Math.max(dp[1], dp[0] - prices[i]);
|
||||
dp[2] = Math.max(dp[2], dp[1] + prices[i]);
|
||||
dp[3] = Math.max(dp[3], dp[2] - prices[i]);
|
||||
dp[4] = Math.max(dp[4], dp[3] + prices[i]);
|
||||
}
|
||||
return dp[4];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LeetCode122_{
|
||||
|
||||
static class Solution {
|
||||
public int maxProfit(int[] prices) {
|
||||
// 只要递增就买入
|
||||
|
||||
int left = 0;
|
||||
int right = 1;
|
||||
int profit = 0;
|
||||
while (right < prices.length) {
|
||||
while (left < right && prices[left] > prices[right]) {
|
||||
left++;
|
||||
}
|
||||
if (prices[left] < prices[right]) {
|
||||
profit += (prices[right] - prices[left]);
|
||||
left = right;
|
||||
}
|
||||
right++;
|
||||
}
|
||||
return profit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Solution1 {
|
||||
public int maxProfit(int[] prices) {
|
||||
/**
|
||||
* dp
|
||||
* dp[i][0] 表示 i天没有股票的时候 手头的现金
|
||||
* - i-1就没有 dp[i-1][0]
|
||||
* - i天刚刚卖 dp[i-1][1]+price[i]
|
||||
* dp[i][1] 表示 i天有股票的时候 手头的现金
|
||||
* - i-1就有 dp[i-1][1]
|
||||
* - 刚刚买入 dp[i-1][0] - price[i]
|
||||
*/
|
||||
int[][] dp = new int[prices.length][2];
|
||||
dp[0][1] = -prices[0];
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
|
||||
}
|
||||
return dp[prices.length - 1][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LeetCode121_ {
|
||||
static class Solution {
|
||||
public int maxProfit(int[] prices) {
|
||||
// 最低点买入,最高点卖出
|
||||
int min = Integer.MAX_VALUE;
|
||||
int res = 0;
|
||||
for (int price : prices) {
|
||||
min = Math.min(min, price);
|
||||
res = Math.max(res, price - min);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Solution2 {
|
||||
public int maxProfit(int[] prices) {
|
||||
int[][] dp = new int[prices.length][2];
|
||||
// 本题只能交易一次
|
||||
// dp[i][0] 表示第i天手里没有股票的 手里的现金
|
||||
// - 第i天卖出 dp[i][0]=dp[i-1][1]+prices[i]
|
||||
// - 第i-1天就没有股票 dp[i][0]=dp[i-1][0]
|
||||
// dp[i][1] 表示第i天手里有股票的 手里的现金
|
||||
// - 第i天买入 dp[i][1] = - prices[i]
|
||||
// - 第i-1天就有 dp[i][1] = dp[i-1][1]
|
||||
dp[0][1] = -prices[0];
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], - prices[i]);
|
||||
}
|
||||
|
||||
return dp[prices.length - 1][0];
|
||||
}
|
||||
}
|
||||
|
||||
static class Solution3 {
|
||||
public int maxProfit(int[] prices) {
|
||||
int[] dp = new int[2];
|
||||
// 本题只能交易一次
|
||||
// dp[i][0] 表示第i天手里没有股票的 手里的现金
|
||||
// - 第i天卖出 dp[i][0]=dp[i-1][1]+prices[i]
|
||||
// - 第i-1天就没有股票 dp[i][0]=dp[i-1][0]
|
||||
// dp[i][1] 表示第i天手里有股票的 手里的现金
|
||||
// - 第i天买入 dp[i][1] = - prices[i]
|
||||
// - 第i-1天就有 dp[i][1] = dp[i-1][1]
|
||||
dp[1] = -prices[0];
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[0] = Math.max(dp[0], dp[1] + prices[i]);
|
||||
dp[1] = Math.max(dp[1], - prices[i]);
|
||||
}
|
||||
|
||||
return dp[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LeetCode309_ {
|
||||
|
||||
class Solution {
|
||||
public int maxProfit(int[] prices) {
|
||||
// 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
|
||||
/**
|
||||
* boolean[] flag
|
||||
* flag[i] 表示第i天是否卖出获得最大利润
|
||||
*
|
||||
* s2 s3
|
||||
* dp[i][0] 表示 第i天手里不持有股票,i-1也不持有,表明在i-1之前卖出股票 手里有的钱
|
||||
* - i不持有 i-1 不持有 i-2不持有 dp[i-2][0]
|
||||
* - i不持有 i-1 不持有 i-2持有,i-1卖出 dp[i-2][2] + prices[i-1]
|
||||
*
|
||||
* s4
|
||||
* dp[i][1] 表示i不持有,i-1持有 手里有的钱
|
||||
* - 今天为冷冻期 i卖出 dp[i-1][2] + prices[i]
|
||||
*
|
||||
* s1
|
||||
* dp[i][2] 表示 第i天持有股票 手里有的钱
|
||||
* - i-1有 dp[i-1][2]
|
||||
* - 前一天是冷冻期 i和i-1都不持有 dp[i-1][0] - price[i]
|
||||
* - 当天是冷冻期 i不持有 i-1持有 dp[i-1][1] - price[i]
|
||||
*
|
||||
*/
|
||||
int[][] dp = new int[prices.length][2];
|
||||
boolean[] flag = new boolean[prices.length];
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
if (dp[i - 1][0] > dp[i - 1][1] + prices[i]) {
|
||||
dp[i][0] = dp[i - 1][0];
|
||||
}else {
|
||||
dp[i][0] = dp[i - 1][1] + prices[i];
|
||||
flag[i] = true;
|
||||
}
|
||||
|
||||
// if
|
||||
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* 状态:
|
||||
* 1. 持有dp[i][0]
|
||||
* - i-1就持有 dp[i-1][0]
|
||||
* - 当天买入
|
||||
* - 前一天是冷冻期 dp[i-1][3] - price[i]
|
||||
* - 前一天不是冷冻期 dp[i-1][1] - price[i]
|
||||
* 2. 不持有
|
||||
* - i-1就不持有,i-2或之前卖出过股票 dp[i][1]
|
||||
* - i-1不持有 i-2不持有 dp[i-1][1]
|
||||
* - i-1不持有 i-2持有,表明i-1卖出了 dp[i-1][2] + price[i]
|
||||
* - 今天卖出 dp[i][2]
|
||||
* - dp[i-1][0]+price[i]
|
||||
*
|
||||
* 3. 冷冻dp[i][3]
|
||||
* - i-1卖出 dp[i-1][2]
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices) {
|
||||
int[][] dp = new int[prices.length][4];
|
||||
dp[0][0] -= prices[0];
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[i][0] = Math.max(dp[i - 1][0], Math.max(dp[i - 1][3] - prices[i], dp[i - 1][1] - prices[i]));
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][3]);
|
||||
dp[i][2] = dp[i - 1][0] + prices[i];
|
||||
dp[i][3] = dp[i - 1][2];
|
||||
}
|
||||
return Math.max(
|
||||
dp[prices.length - 1][3],
|
||||
Math.max(
|
||||
dp[prices.length - 1][1],
|
||||
dp[prices.length - 1][2]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* dp[i][0] 表示第i天手里没有股票的 手里的现金
|
||||
* 1. 当天卖出 dp[i-1][1] + prices[i]
|
||||
* 2. i-1天就没有
|
||||
* dp[i-1][0]
|
||||
* dp[i][1] 表示第i天手里有股票的 手里的现金
|
||||
* 1. 刚刚买入(考虑2天前手里没有股票,i-1天为冷冻期) dp[i-2][0] - prices[i]
|
||||
* 2. i-1就持有 dp[i-1][1]
|
||||
*
|
||||
* 初始化
|
||||
* dp[0][0] = 0
|
||||
* dp[0][1] = -prices[0]
|
||||
* dp[1][0] = Math.max(dp[0][0], dp[0][1] + prices[0]);
|
||||
* dp[1][1] = Math.max(dp[0][1], dp[0][0]-prices[0]);
|
||||
*
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit1(int[] prices) {
|
||||
if(prices.length==1){
|
||||
return 0;
|
||||
}
|
||||
int[][] dp = new int[prices.length][2];
|
||||
dp[0][0] = 0;
|
||||
dp[0][1] = -prices[0];
|
||||
dp[1][0] = Math.max(dp[0][0], dp[0][1] + prices[1]);
|
||||
dp[1][1] = Math.max(dp[0][1], dp[0][0] - prices[1]);
|
||||
for (int i = 2; i < prices.length; i++) {
|
||||
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 2][0] - prices[i]);
|
||||
}
|
||||
return dp[prices.length - 1][0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
int[] prices = new int[]{1, 2, 3, 0, 2};
|
||||
System.out.println(new LeetCode309_().new Solution1().maxProfit1(prices));
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
package cn.whaifree.leetCode.Graph;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/17 16:26
|
||||
* @注释
|
||||
*/
|
||||
public class Kama99 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
int a = scanner.nextInt();
|
||||
int b = scanner.nextInt();
|
||||
int[][] input = new int[a][b];
|
||||
boolean[][] visited = new boolean[a][b];
|
||||
for (int i = 0; i < a; i++) {
|
||||
for (int j = 0; j < b; j++) {
|
||||
input[i][j] = scanner.nextInt();
|
||||
}
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < a; i++) {
|
||||
for (int j = 0; j < b; j++) {
|
||||
if (!visited[i][j] && input[i][j] == 1) {
|
||||
// 没有走过的节点+为陆地(1)
|
||||
res++;
|
||||
method(input, visited, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(res);
|
||||
}
|
||||
public static int method(int[][] input, boolean[][] looking, int x, int y) {
|
||||
int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 表示四个方向
|
||||
|
||||
int res = 0;
|
||||
int[] item = new int[]{x, y};
|
||||
looking[x][y] = true;
|
||||
Deque<int[]> queue = new LinkedList<>();
|
||||
queue.add(item);
|
||||
while (!queue.isEmpty()) {
|
||||
int[] pop = queue.pop();
|
||||
int x1 = pop[0];
|
||||
int y1 = pop[1];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int nextX = x1 + dir[i][0];
|
||||
int nextY = y1 + dir[i][1];
|
||||
if (nextX >= 0 && nextX < input.length && nextY >= 0 && nextY < input[0].length) {
|
||||
if (!looking[nextX][nextY] && input[nextX][nextY] == 1) { // 只有1才遍历,这样就可以保证只在小岛屿内
|
||||
// (下一次的节点)没有遍历过,并且为1,
|
||||
queue.add(new int[]{nextX, nextY});
|
||||
looking[nextX][nextY] = true; // 进入队列就标志看过了
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package cn.whaifree.leetCode.Graph;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/19 16:44
|
||||
* @注释
|
||||
*/
|
||||
public class Kama99_2 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Scanner sc = new Scanner(System.in);
|
||||
int m = sc.nextInt();
|
||||
int n = sc.nextInt();
|
||||
int[][] grid = new int[m][n];
|
||||
boolean[][] visited = new boolean[m][n];
|
||||
for (int i = 0; i < m; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
grid[i][j] = sc.nextInt();
|
||||
}
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < m; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (!visited[i][j] && grid[i][j] == 1) {
|
||||
res++;
|
||||
visited[i][j] = true;
|
||||
depth(grid, visited, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(res);
|
||||
}
|
||||
|
||||
static int[][] direct = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
|
||||
public static void depth(int[][] map, boolean[][] visited, int x, int y) {
|
||||
|
||||
// 深度优先
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int[] ints = direct[i];
|
||||
int nextX = x + ints[0];
|
||||
int nextY = y + ints[1];
|
||||
if (nextX < 0 || nextX >= map.length || nextY < 0 || nextY >= map[0].length) {
|
||||
continue;
|
||||
}
|
||||
if (visited[nextX][nextY]) { // 访问过的不再访问
|
||||
continue;
|
||||
}
|
||||
if (map[nextX][nextY] == 1) {
|
||||
visited[nextX][nextY] = true;
|
||||
depth(map, visited, nextX, nextY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
package cn.whaifree.leetCode.Graph;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/16 0:02
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode207 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int numCourses = 4;
|
||||
int[][] prerequisites = {{1, 0},{0,2},{1,3}};
|
||||
System.out.println(new Solution().canFinish(numCourses, prerequisites));
|
||||
}
|
||||
class Solution {
|
||||
public boolean canFinish(int numCourses, int[][] prerequisites) {
|
||||
List<List<Integer>> graph = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < numCourses; i++) {
|
||||
graph.add(new ArrayList<>());
|
||||
}
|
||||
|
||||
// 统计入度个数
|
||||
int[] inGre = new int[numCourses];
|
||||
for (int i = 0; i < prerequisites.length; i++) {
|
||||
int course = prerequisites[i][0];
|
||||
int preCourse = prerequisites[i][1];
|
||||
graph.get(preCourse).add(course);
|
||||
inGre[course]++;
|
||||
}
|
||||
|
||||
// 对所有入度为0的进入队列
|
||||
Deque<Integer> queue = new ArrayDeque<>();
|
||||
for (int i = 0; i < numCourses; i++) {
|
||||
if (inGre[i] == 0) {
|
||||
queue.add(i);
|
||||
}
|
||||
}
|
||||
// 出对,并去边
|
||||
int exeCount = 0;
|
||||
while (!queue.isEmpty()) {
|
||||
Integer pop = queue.pop();
|
||||
exeCount++;
|
||||
// 遍历这个pop点的出边
|
||||
List<Integer> popOut = graph.get(pop);
|
||||
for (int i = 0; i < popOut.size(); i++) {
|
||||
int deleteSideNode = popOut.get(i);
|
||||
inGre[deleteSideNode]--;
|
||||
if (inGre[deleteSideNode] == 0) {
|
||||
queue.add(deleteSideNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果队列中没有元素了,但还有边,返回false
|
||||
return exeCount == numCourses;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Solution1 {
|
||||
public boolean canFinish(int numCourses, int[][] prerequisites) {
|
||||
// 统计入度个数
|
||||
int[] map = new int[2000];
|
||||
for (int i = 0; i < prerequisites.length; i++) {
|
||||
map[prerequisites[i][0]]++;
|
||||
}
|
||||
// 对所有入度为0的进入队列
|
||||
Deque<Integer> queue = new ArrayDeque<>();
|
||||
for (int i = 0; i < numCourses; i++) {
|
||||
if (map[i] == 0) {
|
||||
queue.add(i);
|
||||
}
|
||||
}
|
||||
// 出对,并去边
|
||||
int exeCount = 0;
|
||||
while (!queue.isEmpty()) {
|
||||
Integer pop = queue.pop();
|
||||
exeCount++;
|
||||
// 遍历所有的边
|
||||
for (int i = 0; i < prerequisites.length; i++) {
|
||||
if (prerequisites[i][1] == pop) {
|
||||
int deleteSideNode = prerequisites[i][0];
|
||||
map[deleteSideNode]--;
|
||||
if (map[deleteSideNode] == 0) {
|
||||
queue.add(deleteSideNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果队列中没有元素了,但还有边,返回false
|
||||
return exeCount == numCourses;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package cn.whaifree.leetCode.Graph;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/9/16 0:44
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode210 {
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] prerequisites = {{1,0},{2,0},{3,1},{3,2}};
|
||||
int[] res = new Solution().findOrder(4, prerequisites);
|
||||
System.out.println(Arrays.toString(res));
|
||||
}
|
||||
|
||||
public int[] findOrder(int numCourses, int[][] prerequisites) {
|
||||
if (numCourses == 0) return new int[0];
|
||||
int[] inDegrees = new int[numCourses];
|
||||
|
||||
|
||||
// 建立入度表
|
||||
for (int[] p : prerequisites) {
|
||||
inDegrees[p[0]]++; // 记录每个节点的入度
|
||||
}
|
||||
// 入度为0的节点队列
|
||||
Queue<Integer> queue = new LinkedList<>();
|
||||
for (int i = 0; i < inDegrees.length; i++) {
|
||||
if (inDegrees[i] == 0) queue.offer(i); // 入度为 0 的节点可以进行执行
|
||||
}
|
||||
int count = 0; // 记录可以执行的任务数
|
||||
int[] res = new int[numCourses]; // 完整拓扑排序的执行过程
|
||||
|
||||
// 根据提供的可以执行的任务(入度为 0),删除入度为 0 的节点
|
||||
while (!queue.isEmpty()){
|
||||
int curr = queue.poll(); // 拿到一个可以执行的任务
|
||||
res[count++] = curr; // 这个任务可以执行,作为下一次执行的节点
|
||||
for (int[] p : prerequisites) {
|
||||
if (p[1] == curr){ // {a,b} 表示 a 依赖 b b-->a
|
||||
inDegrees[p[0]]--;
|
||||
if (inDegrees[p[0]] == 0) queue.offer(p[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count == numCourses) return res;
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
public int[] findOrder(int numCourses, int[][] prerequisites) {
|
||||
List<List<Integer>> graph = new ArrayList<>();
|
||||
for (int i = 0; i < numCourses; i++) {
|
||||
graph.add(new ArrayList<>());
|
||||
}
|
||||
int[] inGre = new int[numCourses];
|
||||
|
||||
Deque<Integer> deque = new LinkedList<>();
|
||||
for (int[] prerequisite : prerequisites) {
|
||||
int course = prerequisite[0];
|
||||
int pre = prerequisite[1];
|
||||
inGre[course]++;
|
||||
graph.get(pre).add(course);
|
||||
}
|
||||
|
||||
for (int i = 0; i < inGre.length; i++) {
|
||||
if (inGre[i] == 0) {
|
||||
deque.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
int exec = 0;
|
||||
int[] res = new int[numCourses];
|
||||
while (!deque.isEmpty()) {
|
||||
Integer exe = deque.pop();
|
||||
res[exec] = exe;
|
||||
exec++;
|
||||
List<Integer> in = graph.get(exe);
|
||||
for (int into = 0; into < in.size(); into++) {
|
||||
Integer intoNode = in.get(into);
|
||||
inGre[intoNode]--;
|
||||
if (inGre[intoNode] == 0) {
|
||||
deque.add(intoNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numCourses == exec) {
|
||||
return res;
|
||||
}
|
||||
return new int[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package cn.whaifree.leetCode.Graph;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/10/17 18:09
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode797 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] graph = {{4,3,1},{3,2,4},{3},{4},{}};
|
||||
List<List<Integer>> res = new Solution().allPathsSourceTarget(graph);
|
||||
res.forEach(System.out::println);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
List<List<Integer>> res = null;
|
||||
List<Integer> path = null;
|
||||
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
|
||||
res = new java.util.ArrayList<>();
|
||||
path = new java.util.ArrayList<>();
|
||||
path.add(0);
|
||||
dfs(graph, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void dfs(int[][] graph, int cur) {
|
||||
if (!path.isEmpty() && graph.length - 1 == path.get(path.size() - 1)) {
|
||||
res.add(new java.util.ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
|
||||
int[] ints = graph[cur];
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
path.add(ints[i]);
|
||||
dfs(graph, ints[i]); // 0-4
|
||||
path.remove(path.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
package cn.whaifree.leetCode.Greedy;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/27 11:42
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode1005 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution().largestSumAfterKNegations(new int[]{-2,5,0,2,-2}, 3));
|
||||
System.out.println(new Solution().largestSumAfterKNegations(new int[]{4,2,3}, 1))
|
||||
;
|
||||
|
||||
System.out.println(new Solution1().largestSumAfterKNegations(new int[]{-2,5,0,2,-2}, 3));
|
||||
System.out.println(new Solution1().largestSumAfterKNegations(new int[]{4,2,3}, 1));
|
||||
}
|
||||
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
* 注意几个例子
|
||||
* 1. nums = [3,-1,0,2], k = 3 选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2]
|
||||
*
|
||||
* -2,5,1,2,-2
|
||||
* 按绝对值逆转 5 -2 2 -2 1
|
||||
* 每次遇到负数,变为相反数
|
||||
* // 剩下的k如果是奇数,就把最后一个逆转
|
||||
*
|
||||
* @param nums
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public int largestSumAfterKNegations(int[] nums, int k) {
|
||||
// 按绝对值从大到小排序,对前k个负数进行相反数
|
||||
nums = IntStream.of(nums)
|
||||
.boxed()
|
||||
.sorted((o1, o2) -> Math.abs(o2) - Math.abs(o1))
|
||||
.mapToInt(Integer::intValue).toArray();
|
||||
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (k > 0 && nums[i] < 0) {
|
||||
nums[i] = -nums[i];
|
||||
k--;
|
||||
}
|
||||
}
|
||||
|
||||
// 此时还有k个没减去,k为偶数则不管,k为奇数就把最小那个变为正数
|
||||
if (k % 2 == 1) {
|
||||
nums[nums.length-1] = -nums[nums.length-1];
|
||||
}
|
||||
|
||||
|
||||
return Arrays.stream(nums).sum();
|
||||
}
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
|
||||
/**
|
||||
* 注意几个例子
|
||||
* 1. nums = [3,-1,0,2], k = 3 选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2]
|
||||
*
|
||||
* -2,5,1,2,-2
|
||||
* 排序
|
||||
* -2 -2 1 2 5
|
||||
* 逆转
|
||||
* 2 2 1 2 5
|
||||
* 将最下的数逆转,sum-min-min
|
||||
* 2 2 -1 2 5
|
||||
*
|
||||
* @param nums
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public int largestSumAfterKNegations(int[] nums, int k) {
|
||||
// 按绝对值从大到小排序,对前k个负数进行相反数
|
||||
Arrays.sort(nums);
|
||||
|
||||
|
||||
int sum = 0;
|
||||
int minValue = Integer.MAX_VALUE;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (k > 0 && nums[i] < 0) {
|
||||
nums[i] = -nums[i];
|
||||
k--;
|
||||
}
|
||||
sum += nums[i];
|
||||
minValue = Math.min(minValue, nums[i]);
|
||||
}
|
||||
|
||||
// 此时还有k个没减去,k为偶数则不管,k为奇数就把最小那个变为正数
|
||||
if (k % 2 == 1) {
|
||||
// 减去在遍历过程中加的minValue部分和通过变换负数的部分
|
||||
return sum - minValue - minValue;
|
||||
}else {
|
||||
return sum;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
package cn.whaifree.leetCode.Greedy;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/25 22:21
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode122 {
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
System.out.println(new Solution1().maxProfit(new int[]{7, 1, 5, 3, 6, 4}));
|
||||
|
||||
System.out.println(new Solution1().maxProfit(new int[]{1}));
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
|
||||
/**
|
||||
* 随时可以买卖,那么只要有跌的我都不要。
|
||||
* 上帝视角:只要涨我就全要
|
||||
*
|
||||
* 7跌 1涨5 跌 4涨6 跌4
|
||||
*
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices) {
|
||||
|
||||
int maxProfit = 0;
|
||||
for (int i = 0; i < prices.length; i++) {
|
||||
if (i > 0 && prices[i] - prices[i - 1] > 0) {
|
||||
maxProfit += prices[i] - prices[i - 1];
|
||||
}
|
||||
}
|
||||
return maxProfit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
|
||||
/**
|
||||
* dp[i] 表示当天可获得的收益
|
||||
* dp[i] = dp[i-1] + if(prices[i-1] < price[i]){prices[i] - price[i-1]}
|
||||
*
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices) {
|
||||
int[] dp = new int[prices.length];
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[i] = dp[i - 1];
|
||||
if (prices[i - 1] < prices[i]) {
|
||||
// 挣钱
|
||||
dp[i] += prices[i] - prices[i - 1];
|
||||
}
|
||||
}
|
||||
return dp[prices.length - 1];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
package cn.whaifree.leetCode.Greedy;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/2/27 20:02
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode134 {
|
||||
|
||||
@Test
|
||||
public void test() throws InterruptedException {
|
||||
|
||||
System.out.println("初始化内存 -Xms");
|
||||
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024 + "m");
|
||||
|
||||
System.out.println("最大可使用内存 :");
|
||||
System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024 + "m");
|
||||
|
||||
System.out.println("最大堆内存:-Xmx");
|
||||
System.out.println(Runtime.getRuntime().maxMemory() / 1024 / 1024 + "m");
|
||||
|
||||
// -XX+PrintGCDetails
|
||||
|
||||
int[] ints = new int[10000];
|
||||
// Thread.sleep(1000000);
|
||||
|
||||
// System.out.println(new Solution().canCompleteCircuit(
|
||||
// new int[]{5,1,2,3,4},
|
||||
// new int[]{4,4,1,5,1}
|
||||
// ));
|
||||
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
*
|
||||
* @param gas 加油站有的油
|
||||
* @param cost 行驶代价
|
||||
* @return
|
||||
*/
|
||||
public int canCompleteCircuit(int[] gas, int[] cost) {
|
||||
|
||||
int[] rent = new int[gas.length];
|
||||
int total = 0;
|
||||
for (int i = 0; i < gas.length; i++) {
|
||||
rent[i] = gas[i] - cost[i];
|
||||
total += rent[i];
|
||||
}
|
||||
// 如果全部剩余<0 则必然跑不了一圈
|
||||
if (total < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// 以下为必然可以跑一圈的
|
||||
// 如果当前剩余不够用,则让指针指向i+1
|
||||
int curSum = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < rent.length; i++) {
|
||||
curSum += rent[i];
|
||||
if (curSum < 0) {
|
||||
index = (i + 1) % gas.length ;
|
||||
curSum = 0;
|
||||
}
|
||||
}
|
||||
// 1. 前提,必然能跑一圈
|
||||
// 2. 没有进入某个i之后都没有curSum<0 那么就是正确的i
|
||||
return index;
|
||||
}
|
||||
|
||||
}
|
||||
// class Solution {
|
||||
// /**
|
||||
// *
|
||||
// * @param gas 加油站有的油
|
||||
// * @param cost 行驶代价
|
||||
// * @return
|
||||
// */
|
||||
// public int canCompleteCircuit(int[] gas, int[] cost) {
|
||||
// int needSum = 0;
|
||||
// for (int i : cost) {
|
||||
// needSum += i;
|
||||
// }
|
||||
//
|
||||
// int iHave = 0;
|
||||
// int sumAdd = 0;
|
||||
// int start = 0;
|
||||
// for (int i = 0; i < gas.length; i++) {
|
||||
// iHave += gas[i];
|
||||
// sumAdd += gas[i];
|
||||
// if (iHave < cost[i]) {
|
||||
// iHave = 0;
|
||||
// i = start;
|
||||
// start = start + 1;
|
||||
// sumAdd = 0;
|
||||
// continue;
|
||||
// }
|
||||
// iHave -= cost[i];
|
||||
// if (sumAdd >= needSum) {
|
||||
// return start;
|
||||
// }
|
||||
//
|
||||
// if (i == gas.length - 1) {
|
||||
// i = -1;
|
||||
// }
|
||||
//
|
||||
// if (start == gas.length - 1 && start != i) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user