Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions problems/0001.两数之和.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,25 @@ public:

### Java:

```java
// 暴力解法
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
result[0] = i;
result[1] = j;
return result;
}
}
}
return null;
}
}
```

```java
//使用哈希表
public int[] twoSum(int[] nums, int target) {
Expand Down
20 changes: 20 additions & 0 deletions problems/0053.最大子序和(动态规划).md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,26 @@ public:

### Java:

```java
// 模拟贪心思路
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length]; // dp[i]表示以nums[i]结尾的最大子数组和
int result = nums[0]; // 记录最大和
dp[0] = nums[0]; // 子数组最少包含一个元素所以要初始化为nums[0]
for (int i = 1; i < nums.length; i++) {
if (dp[i - 1] >= 0) {
dp[i] = dp[i - 1] + nums[i];
} else {
dp[i] = nums[i];
}
result = Math.max(result,dp[i]); // 时刻更新最大和
}
return result;
}
}
```

```java
/**
* 1.dp[i]代表当前下标对应的最大值
Expand Down
34 changes: 34 additions & 0 deletions problems/0112.路径总和.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,40 @@ public:

0112.路径总和

```java
// 递归法
class Solution {
private int sum; // 记录路径总和
private boolean result = false; // result默认为false
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return result; // 如果root为空直接返回false
}
sum = root.val; // 不为空就先把root的值先加进去
traversal(root,targetSum); // 开始递归
return result;
}
public void traversal(TreeNode cur, int targetSum) {
if (cur.left == null && cur.right == null) { // 访问到叶子结点的时候就可以尝试修改result的值了
if (sum == targetSum) { // 如果当前路径的sum等于目标值就把result修改为true
result = true;
}
return; // 否则就return
}
if (cur.left != null) {
sum += cur.left.val; // 向左递归前先把这个路径值加上cur.left的val
traversal(cur.left,targetSum);
sum -= cur.left.val; // 回溯
}
if (cur.right != null) {
sum += cur.right.val;
traversal(cur.right,targetSum);
sum -= cur.right.val;
}
}
}
```

```java
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
Expand Down
33 changes: 33 additions & 0 deletions problems/0122.买卖股票的最佳时机II.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,39 @@ public:

### Java:

模拟:
```java
// 模拟法
class Solution {
public int maxProfit(int[] prices) {
int curDiff = 0; // 记录后一天和当天的股票价值差
int buy = -1; // 记录购买时的股票价格
List<Integer> result = new ArrayList<>(); // 记录每次赚取的利润
for (int i = 0; i < prices.length - 1; i++) { // 遍历到倒数第二个
curDiff = prices[i + 1] - prices[i]; // 更新curDiff
if (curDiff > 0 && buy == -1) { // 如果curDiff大于0而且还没有购买股票buy=0的时候就要买了
buy = prices[i]; // 记录购买股票的价格
} else if (curDiff < 0 && buy != -1) { // 一旦发现后一天的股票价格低于当天股票价格,而且已经买了股票了buy!=0,就要及时抛售
int sell = prices[i]; // 记录当天价格作为出售价格
int profit = sell - buy; // 记录利润
result.add(profit); // 加入利润集合中
buy = -1; // 重置buy,相当于手上没股票
}
if (buy != -1 && i == prices.length - 2 && curDiff >= 0) { // 处理末尾情况,即存在一个片段单调递增一直到最后一天,此时就是已经购买了股票而且遍历到倒数第二天了,curDiff仍旧大于0,那么就选择最后一天出售股票,获取最大利润
int sell = prices[i + 1]; // 最后一天股票价格作为出售价格
int profit = sell - buy; // 计算利润
result.add(profit);
}
}
int sum = 0;
for (int i : result) {
sum += i; // 利润总和
}
return sum;
}
}
```

贪心:

```java
Expand Down
53 changes: 53 additions & 0 deletions problems/0151.翻转字符串里的单词.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,59 @@ public:

### Java:

```java
// 双指针+数组覆盖
class Solution {
public String reverseWords(String s) {
char[] arr = s.toCharArray(); // 字符串不可变转换为数组处理
while (arr[arr.length - 1] == ' ') { // 截断原字符串的尾部所有空格
arr = Arrays.copyOf(arr,arr.length - 1);
}
int left = 0; // 设置左右指针,利用数组对称性完成字符串的颠倒
int right = arr.length - 1;
while (left < right) {
arr[left] ^= arr[right];
arr[right] ^= arr[left];
arr[left] ^= arr[right];
left++;
right--;
}
while (arr[arr.length - 1] == ' ') { // 去除颠倒后的字符串的尾部空格,这样结果字符串两端都没有空格了,之所以去除尾部空格是避免不必要的数组元素移动的时间消耗
arr = Arrays.copyOf(arr,arr.length - 1);
}
left = 0; // 重置左指针为0
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] == ' ' && arr[i + 1] != ' ') { // 遇到新单词重置左指针
left = i + 1;
} else if ((arr[i] !=' ' && arr[i + 1] == ' ') || i == arr.length - 2) { // 中间遇到空格了或是遍历到结尾了,设置或重置右指针,一旦设置右指针就可以开始单词的局部调换。但两种情况的右指针设置不同。
right = i != arr.length - 2 ? i : arr.length - 1; // 中间遇到空格那么右指针就设为i,遍历到尾部了右指针就设置为最后一个元素
while (right > left) {
arr[left] ^= arr[right];
arr[right] ^= arr[left];
arr[left] ^= arr[right];
left++;
right--;
}
} else {
continue; // 在单词之中遍历,由于不用设置指针跳过即可
}
}
int count = 0; // 记录中间多余的空格数
for (int i = 0; i < arr.length; i++) {
if (arr[i] == ' ' && arr[i + 1] == ' ') { // 遇到连续空格
for (int j = i + 1; j < arr.length; j++) { // 第二个空格后的所有元素向左移动一位目的是清除第二个空格
arr[j - 1] = arr[j];
}
count++; // 多余空格数记录加一
i--; // 由于遇到了了连续空格后面数组往前移动了,所以i相对地往前移动了已经,所以要i--配合循环结束后的i++保证i不移动。eg:连续三个空格的时候如果此时不i--,虽然删除了第二个空格,可是指针i会移动到原第三个空格上,这样就无法对原第三个空格进行删除操作,就会多出来一个空格。
}
}
arr = Arrays.copyOf(arr,arr.length - count); // 把数组移动覆盖多余空格后尾部的多余元素要截断
return new String(arr);
}
}
```

```Java
class Solution {
/**
Expand Down
28 changes: 28 additions & 0 deletions problems/0206.翻转链表.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,34 @@ public:

### Java:

```java
// 双指针
class Solution {
public ListNode reverseList(ListNode head) {
// 处理空链表或单节点情况
if (head == null || head.next == null) {
return head;
}
// pre: 已反转部分的最后一个节点
ListNode pre = head;
// cur: 待反转部分的第一个节点
ListNode cur = head.next;
while (cur != null) {
// 1. 用head.next临时保存cur的下一个节点
head.next = cur.next;
// 2. 反转当前节点的指针
cur.next = pre;
// 3. pre右移到cur的位置(移动已反转部分边界)
pre = cur;
// 4. cur右移到下一个待处理节点
cur = head.next;
}
// pre最终指向新链表的头节点
return pre;
}
}
```

```java
// 双指针
class Solution {
Expand Down
23 changes: 23 additions & 0 deletions problems/0349.两个数组的交集.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,29 @@ public:
## 其他语言版本

### Java:
暴力解法
```Java
// 暴力解法(HashSet)
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
HashSet<Integer> set = new HashSet<Integer>(); // 创建一个HashSet用于作为中转站,保证输出结果中的每一个元素一定是唯一的
for (int i = 0; i < nums1.length; i++) { // 暴力法遍历,主num1副num2,外层num1因为只遍历一次,所以我们添加num1元素
for (int j = 0; j < nums2.length; j++) {
if (nums1[i] == nums2[j]) { // 如果一旦两个数组存在交集,添加当前num1元素并且退出内循环进入下一次外循环当中
set.add(nums1[i]); // 添加交集元素
break; // 退出当前内循环
}
}
}
int[] array = new int[set.size()]; // 题目要求返回int类型数组,创建int类型数组,把HashSet的元素一一塞入数组中
int i = 0;
for (int num: set) {
array[i++] = num;
}
return array;
}
}
```
版本一:使用HashSet
```Java
// 时间复杂度O(n+m+k) 空间复杂度O(n+k)
Expand Down
22 changes: 22 additions & 0 deletions problems/0452.用最少数量的箭引爆气球.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,28 @@ public:


### Java

```java
// 贪心算法
class Solution {
public int findMinArrowShots(int[][] points) {
if (points.length == 0) {
return 0;
}
int count = 1; // 记录引爆全部气球最少数量的箭,至少一个初始值置为1
Arrays.sort(points,(a,b) -> Integer.compare(a[1],b[1])); // 对数组进行按照右边界升序排序
int lastShoot = points[0][1]; // 最开始的箭射在第一个气球的右边界,本题贪心所在,让一支箭尽可能射到更多的气球
for (int i = 1; i < points.length; i++) {
if (points[i][0] > lastShoot) { // 如果当前气球左边界不包含在上一个射出的箭内,说明还需要一支箭,同初次贪心一样把箭射在当前气球的右边界
count++;
lastShoot = points[i][1];
}
}
return count;
}
}
```

```java
/**
* 时间复杂度 : O(NlogN) 排序需要 O(NlogN) 的复杂度
Expand Down
34 changes: 34 additions & 0 deletions problems/0501.二叉搜索树中的众数.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,40 @@ public:

暴力法

```java
class Solution {
Map<Integer,Integer> map = new HashMap<>(); // 定义全局Map用来记录每个节点出现的次数
public int[] findMode(TreeNode root) {
traversal(root); // 开始递归
List<Integer> result = new ArrayList<>(); // 记录众数元素
int maxValue = Integer.MIN_VALUE; // 记录出现次数最大值
for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
int value = entry.getValue(); // 获取该key的出现次数
if (value > maxValue) { // 更新maxValue,清空原来的result,添加新的元素
maxValue = value;
result.clear();
result.add(entry.getKey());
} else if (value == maxValue) { // 添加别的出现次数一样多的众数
result.add(entry.getKey());
}
}
int[] res = new int[result.size()]; // 把集合转换为数组
for (int i = 0; i < result.size(); i++) {
res[i] = result.get(i);
}
return res;
}
public void traversal(TreeNode cur) {
if (cur == null) { // 遍历到叶子节点返回
return;
}
traversal(cur.left); // 中序遍历
map.put(cur.val,map.getOrDefault(cur.val,0) + 1); // 每个节点出现就往map对应key的value+1
traversal(cur.right);
}
}
```

```java
class Solution {
public int[] findMode(TreeNode root) {
Expand Down
25 changes: 25 additions & 0 deletions problems/0541.反转字符串II.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,31 @@ char * reverseStr(char * s, int k){

### Java:

```java
// 双指针
class Solution {
public String reverseStr(String s, int k) {
char[] arr = s.toCharArray(); // 由于字符串的不可变性,所以要想反转字符串需要先把其转化为数组
int length = s.length(); // 表示尚未遍历过的字符长度
int index = 0; // 表示当下2k组中的初始索引
while (length > 0) { // 遍历完所有的字符串字符,循环结束完成所有反转操作
int left = index; // 左指针为当下2k组的初始位置
int right = length < k ? index + length - 1 : index + k - 1; // 右指针按照题意分为两种情况,第一种是剩余字符少于k,那么操作是将剩余字符全部反转,所有右指针指向整个字符串最后一个字符(收尾阶段)。另一种情况就是剩余字符大于或等于k个的时候,不论是小于2k个还是大于等于2k个,右指针的设置都是在左指针的k个后。
while (left < right) { // 与反转字符串题相似利用对称性进行字符串调换
char temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
length = length - 2 * k; // 由于一次遍历2k个,所以尚未遍历过的字符长度-2k
index = index + 2 * k; // 索引同理移动2k个
}
return new String(arr); // 把字符数组转成字符串返回
}
}
```

```Java
//解法一
class Solution {
Expand Down
27 changes: 27 additions & 0 deletions problems/kamacoder/0055.右旋字符串.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,33 @@ int main() {
## 其他语言版本

### Java:

```java
import java.util.Scanner;
import java.util.Arrays;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int k = sc.nextInt();
String s = sc.next();
char[] arr = s.toCharArray();
int length = arr.length + k; //扩容把原数组填到k后面的位置中,避免填充时流失元素
char[] newArr = new char[length];
int index = k;
for (char a : arr) { // 填充原数组到新数组中
newArr[index] = a;
index++;
}
index = length - k; // 把倒数k个元素移动至开头
for (int i = 0; i < k; i++) {
newArr[i] = newArr[index++];
}
newArr = Arrays.copyOf(newArr,length - k); // 截断后面不需要的k个元素
System.out.println(new String(newArr));
}
}
```

```Java
// 版本一
import java.util.Scanner;
Expand Down
Loading