修改LeetCode目录结构,不分类

This commit is contained in:
whaifree 2024-10-28 14:47:24 +08:00
parent 25f4784daa
commit aee514923d
250 changed files with 1187 additions and 21337 deletions

View File

@ -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>

View 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);
}
}
}
}

View 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;
// }
// }
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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}));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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}));
}
}

View File

@ -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;
}
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}
}

View File

@ -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];
}
}
}

View File

@ -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修改回为02修改回为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;
}
}
}
}
}
}

View File

@ -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();
}

View File

@ -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) {
//
// }
// }
}

View File

@ -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) {
// [leftmiddle) , (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);
}
}
}

View File

@ -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左边的值一直保持小于targetright右边的值一直保持大于等于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));
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -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);
}
}

View File

@ -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]);
}
}
}

View File

@ -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]]*/
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
// }
// }
}

View File

@ -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]);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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表示还没从递归中出来即是11中的第二个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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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. 选择点进行填充
* 填充后判断该点上列斜4545度角是否有被使用过
* - 如果有回溯到上次递归
* - 没有标记该点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;
}
}
// 判断斜45135度 该点右边上搜索
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
// 只要让某个点不断往斜45度向左上检查就可以
if (chessMap[i][j] == 'Q') {
return false;
}
}
return true;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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];
}
}

View File

@ -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如果容量为123只能放物品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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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-1nums2从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];
}
}
}

View File

@ -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;
}
}
}

View File

@ -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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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;
}
}
}

View File

@ -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..i1] 是否能被空格拆分成若干个字典中出现的单词
*
* 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"));
}
}

View File

@ -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];
}
}
}

View File

@ -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循环遍历物品 10 01
// 本题都可以
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];
}
}
}

View File

@ -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包含ii在每次循环中是最后一个的最长递增子序列的长度
*/
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;
}
}
}

View File

@ -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];
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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] = nulldp[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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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;
}
}
}

View File

@ -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] = maxdp[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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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种因为没有元素所以只能不选和为0dp[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));
}
}

View File

@ -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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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;
}
}
}

View File

@ -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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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
* 初始化 dp0,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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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;
}
}
}

View File

@ -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];
}
}
}

View File

@ -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];
}
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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];
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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];
}
}
}

View File

@ -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