Merge pull request #39 from nanhuaibeian/master

添加0039.组合总和/0040.组合总和II /0045.跳跃游戏II /0055.跳跃游戏/0322.零钱兑换 /0377.组合总和IV /0383.赎金信 /0416.分割等和子集 /0454.四数相加 /0474.一和零 /0518.零钱兑换II /0707.设计链表/0746.使用最小花费爬楼梯 Java版本
This commit is contained in:
Carl Sun
2021-05-12 21:23:53 +08:00
committed by GitHub
13 changed files with 380 additions and 7 deletions

View File

@ -236,7 +236,39 @@ public:
Java
```Java
class Solution {
List<List<Integer>> lists = new ArrayList<>();
Deque<Integer> deque = new LinkedList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
backTracking(arr, n, k, 0);
return lists;
}
public void backTracking(int[] arr, int n, int k, int startIndex) {
//如果 n 小于0没必要继续本次递归已经不符合要求了
if (n < 0) {
return;
}
if (deque.size() == k) {
if (n == 0) {
lists.add(new ArrayList(deque));
}
return;
}
for (int i = startIndex; i < arr.length - (k - deque.size()) + 1; i++) {
deque.push(arr[i]);
//减去当前元素
n -= arr[i];
backTracking(arr, n, k, i + 1);
//恢复n
n += deque.pop();
}
}
}
```
Python

View File

@ -255,7 +255,43 @@ public:
Java
```Java
class Solution {
List<List<Integer>> lists = new ArrayList<>();
Deque<Integer> deque = new LinkedList<>();
int sum = 0;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
//为了将重复的数字都放到一起,所以先进行排序
Arrays.sort(candidates);
//加标志数组,用来辅助判断同层节点是否已经遍历
boolean[] flag = new boolean[candidates.length];
backTracking(candidates, target, 0, flag);
return lists;
}
public void backTracking(int[] arr, int target, int index, boolean[] flag) {
if (sum == target) {
lists.add(new ArrayList(deque));
return;
}
for (int i = index; i < arr.length && arr[i] + sum <= target; i++) {
//出现重复节点,同层的第一个节点已经被访问过,所以直接跳过
if (i > 0 && arr[i] == arr[i - 1] && !flag[i - 1]) {
continue;
}
flag[i] = true;
sum += arr[i];
deque.push(arr[i]);
//每个节点仅能选择一次,所以从下一位开始
backTracking(arr, target, i + 1, flag);
int temp = deque.pop();
flag[i] = false;
sum -= temp;
}
}
}
```
Python

View File

@ -143,7 +143,36 @@ public:
Java
```Java
class Solution {
public int jump(int[] nums) {
if (nums == null || nums.length == 0 || nums.length == 1) {
return 0;
}
//记录跳跃的次数
int count=0;
//当前的覆盖最大区域
int curDistance = 0;
//最大的覆盖区域
int maxDistance = 0;
for (int i = 0; i < nums.length; i++) {
//在可覆盖区域内更新最大的覆盖区域
maxDistance = Math.max(maxDistance,i+nums[i]);
//说明当前一步,再跳一步就到达了末尾
if (maxDistance>=nums.length-1){
count++;
break;
}
//走到当前覆盖的最大区域时,更新下一步可达的最大区域
if (i==curDistance){
curDistance = maxDistance;
count++;
}
}
return count;
}
}
```
Python

View File

@ -86,7 +86,25 @@ public:
Java
```Java
class Solution {
public boolean canJump(int[] nums) {
if (nums.length == 1) {
return true;
}
//覆盖范围
int coverRange = nums[0];
//在覆盖范围内更新最大的覆盖范围
for (int i = 0; i <= coverRange; i++) {
coverRange = Math.max(coverRange, i + nums[i]);
if (coverRange >= nums.length - 1) {
return true;
}
}
return false;
}
}
```
Python

View File

@ -181,7 +181,31 @@ public:
Java
```Java
class Solution {
public int coinChange(int[] coins, int amount) {
int max = Integer.MAX_VALUE;
int[] dp = new int[amount + 1];
//初始化dp数组为最大值
for (int j = 0; j < dp.length; j++) {
dp[j] = max;
}
//当金额为0时需要的硬币数目为0
dp[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]] != max) {
//选择硬币数目最小的情况
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
}
return dp[amount] == max ? -1 : dp[amount];
}
}
```
Python

View File

@ -147,7 +147,23 @@ C++测试用例有超过两个树相加超过int的数据所以需要在if里
Java
```Java
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
dp[0] = 1;
for (int i = 0; i <= target; i++) {
for (int j = 0; j < nums.length; j++) {
if (i >= nums[j]) {
dp[i] += dp[i - nums[j]];
}
}
}
return dp[target];
}
}
```
Python

View File

@ -111,7 +111,31 @@ public:
Java
```Java
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
//记录杂志字符串出现的次数
int[] arr = new int[26];
int temp;
for (int i = 0; i < magazine.length(); i++) {
temp = magazine.charAt(i) - 'a';
arr[temp]++;
}
for (int i = 0; i < ransomNote.length(); i++) {
temp = ransomNote.charAt(i) - 'a';
//对于金信中的每一个字符都在数组中查找
//找到相应位减一否则找不到返回false
if (arr[temp] > 0) {
arr[temp]--;
} else {
return false;
}
}
return true;
}
}
```
Python

View File

@ -185,7 +185,41 @@ public:
Java
```Java
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int i : nums) {
sum += i;
}
if ((sum & 1) == 1) {
return false;
}
int length = nums.length;
int target = sum >> 1;
//dp[j]表示前i个元素可以找到相加等于j情况
boolean[] dp = new boolean[target + 1];
//对于第一个元素只有当j=nums[0]时,才恰好填充满
if (nums[0] <= target) {
dp[nums[0]] = true;
}
for (int i = 1; i < length; i++) {
//j由右往左直到nums[i]
for (int j = target; j >= nums[i]; j--) {
//只有两种情况,要么放,要么不放
//取其中的TRUE值
dp[j] = dp[j] || dp[j - nums[i]];
}
//一旦满足,结束,因为只需要找到一组值即可
if (dp[target]) {
return dp[target];
}
}
return dp[target];
}
}
```
Python

View File

@ -88,7 +88,36 @@ public:
Java
```Java
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer, Integer> map = new HashMap<>();
int temp;
int res = 0;
//统计两个数组中的元素之和同时统计出现的次数放入map
for (int i : nums1) {
for (int j : nums2) {
temp = i + j;
if (map.containsKey(temp)) {
map.put(temp, map.get(temp) + 1);
} else {
map.put(temp, 1);
}
}
}
//统计剩余的两个元素的和在map中找是否存在相加为0的情况同时记录次数
for (int i : nums3) {
for (int j : nums4) {
temp = i + j;
if (map.containsKey(0 - temp)) {
res += map.get(0 - temp);
}
}
}
return res;
}
}
```
Python

View File

@ -161,7 +161,33 @@ public:
Java
```Java
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
//dp[i][j]表示i个0和j个1时的最大子集
int[][] dp = new int[m + 1][n + 1];
int oneNum, zeroNum;
for (String str : strs) {
oneNum = 0;
zeroNum = 0;
for (char ch : str.toCharArray()) {
if (ch == '0') {
zeroNum++;
} else {
oneNum++;
}
}
//倒序遍历
for (int i = m; i >= zeroNum; i--) {
for (int j = n; j >= oneNum; j--) {
dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
}
}
}
return dp[m][n];
}
}
```
Python

View File

@ -188,7 +188,22 @@ public:
Java
```Java
class Solution {
public int change(int amount, int[] coins) {
//递推表达式
int[] dp = new int[amount + 1];
//初始化dp数组表示金额为0时只有一种情况也就是什么都不装
dp[0] = 1;
for (int i = 0; i < coins.length; i++) {
for (int j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
```
Python

View File

@ -157,7 +157,78 @@ private:
Java
```Java
class MyLinkedList {
//size存储链表元素的个数
int size;
//虚拟头结点
ListNode head;
//初始化链表
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
//获取第index个节点的数值
public int get(int index) {
//如果index非法返回-1
if (index < 0 || index >= size) {
return -1;
}
ListNode currentNode = head;
//包含一个虚拟头节点,所以查找第 index+1 个节点
for (int i = 0; i <= index; i++) {
currentNode = currentNode.next;
}
return currentNode.val;
}
//在链表最前面插入一个节点
public void addAtHead(int val) {
addAtIndex(0, val);
}
//在链表的最后插入一个节点
public void addAtTail(int val) {
addAtIndex(size, val);
}
// 在第 index 个节点之前插入一个新节点例如index为0那么新插入的节点为链表的新头节点。
// 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果 index 大于链表的长度,则返回空
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
if (index < 0) {
index = 0;
}
size++;
//找到要插入节点的前驱
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pred.next;
pred.next = toAdd;
}
//删除第index个节点
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
}
```
Python

View File

@ -203,7 +203,26 @@ public:
Java
```Java
class Solution {
public int minCostClimbingStairs(int[] cost) {
if (cost == null || cost.length == 0) {
return 0;
}
if (cost.length == 1) {
return cost[0];
}
int[] dp = new int[cost.length];
dp[0] = cost[0];
dp[1] = cost[1];
for (int i = 2; i < cost.length; i++) {
dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
}
//最后一步,如果是由倒数第二步爬,则最后一步的体力花费可以不用算
return Math.min(dp[cost.length - 1], dp[cost.length - 2]);
}
}
```
Python