This commit is contained in:
unknown 2022-06-23 10:31:39 +01:00
commit ed3f6a0cde
125 changed files with 5457 additions and 339 deletions

View File

@ -275,5 +275,48 @@ class Solution {
}
```
Scala:
```scala
object Solution {
// 导入包
import scala.collection.mutable
def twoSum(nums: Array[Int], target: Int): Array[Int] = {
// key存储值value存储下标
val map = new mutable.HashMap[Int, Int]()
for (i <- nums.indices) {
val tmp = target - nums(i) // 计算差值
// 如果这个差值存在于map则说明找到了结果
if (map.contains(tmp)) {
return Array(map.get(tmp).get, i)
}
// 如果不包含把当前值与其下标放到map
map.put(nums(i), i)
}
// 如果没有找到直接返回一个空的数组return关键字可以省略
new Array[Int](2)
}
}
```
C#:
```csharp
public class Solution {
public int[] TwoSum(int[] nums, int target) {
Dictionary<int ,int> dic= new Dictionary<int,int>();
for(int i=0;i<nums.Length;i++){
int imp= target-nums[i];
if(dic.ContainsKey(imp)&&dic[imp]!=i){
return new int[]{i, dic[imp]};
}
if(!dic.ContainsKey(nums[i])){
dic.Add(nums[i],i);
}
}
return new int[]{0, 0};
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -616,6 +616,49 @@ public class Solution
}
}
```
Scala:
```scala
object Solution {
// 导包
import scala.collection.mutable.ListBuffer
import scala.util.control.Breaks.{break, breakable}
def threeSum(nums: Array[Int]): List[List[Int]] = {
// 定义结果集最后需要转换为List
val res = ListBuffer[List[Int]]()
val nums_tmp = nums.sorted // 对nums进行排序
for (i <- nums_tmp.indices) {
// 如果要排的第一个数字大于0直接返回结果
if (nums_tmp(i) > 0) {
return res.toList
}
// 如果i大于0并且和前一个数字重复则跳过本次循环相当于continue
breakable {
if (i > 0 && nums_tmp(i) == nums_tmp(i - 1)) {
break
} else {
var left = i + 1
var right = nums_tmp.length - 1
while (left < right) {
var sum = nums_tmp(i) + nums_tmp(left) + nums_tmp(right) // 求三数之和
if (sum < 0) left += 1
else if (sum > 0) right -= 1
else {
res += List(nums_tmp(i), nums_tmp(left), nums_tmp(right)) // 如果等于0 添加进结果集
// 为了避免重复对left和right进行移动
while (left < right && nums_tmp(left) == nums_tmp(left + 1)) left += 1
while (left < right && nums_tmp(right) == nums_tmp(right - 1)) right -= 1
left += 1
right -= 1
}
}
}
}
}
// 最终返回需要转换为Listreturn关键字可以省略
res.toList
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -522,6 +522,49 @@ public class Solution
}
}
```
Scala:
```scala
object Solution {
// 导包
import scala.collection.mutable.ListBuffer
import scala.util.control.Breaks.{break, breakable}
def fourSum(nums: Array[Int], target: Int): List[List[Int]] = {
val res = ListBuffer[List[Int]]()
val nums_tmp = nums.sorted // 先排序
for (i <- nums_tmp.indices) {
breakable {
if (i > 0 && nums_tmp(i) == nums_tmp(i - 1)) {
break // 如果该值和上次的值相同跳过本次循环相当于continue
} else {
for (j <- i + 1 until nums_tmp.length) {
breakable {
if (j > i + 1 && nums_tmp(j) == nums_tmp(j - 1)) {
break // 同上
} else {
// 双指针
var (left, right) = (j + 1, nums_tmp.length - 1)
while (left < right) {
var sum = nums_tmp(i) + nums_tmp(j) + nums_tmp(left) + nums_tmp(right)
if (sum == target) {
// 满足要求,直接加入到集合里面去
res += List(nums_tmp(i), nums_tmp(j), nums_tmp(left), nums_tmp(right))
while (left < right && nums_tmp(left) == nums_tmp(left + 1)) left += 1
while (left < right && nums_tmp(right) == nums_tmp(right - 1)) right -= 1
left += 1
right -= 1
} else if (sum < target) left += 1
else right -= 1
}
}
}
}
}
}
}
// 最终返回的res要转换为Listreturn关键字可以省略
res.toList
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -39,7 +39,7 @@
分为如下几步:
* 首先这里我推荐大家使用虚拟头结点,这样方处理删除实际头结点的逻辑,如果虚拟头结点不清楚,可以看这篇: [链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)
* 首先这里我推荐大家使用虚拟头结点,这样方便处理删除实际头结点的逻辑,如果虚拟头结点不清楚,可以看这篇: [链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)
* 定义fast指针和slow指针初始值为虚拟头结点如图
@ -289,6 +289,28 @@ func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
return dummyHead.next
}
```
Scala:
```scala
object Solution {
def removeNthFromEnd(head: ListNode, n: Int): ListNode = {
val dummy = new ListNode(-1, head) // 定义虚拟头节点
var fast = head // 快指针从头开始走
var slow = dummy // 慢指针从虚拟头开始头
// 因为参数 n 是不可变量,所以不能使用 while(n>0){n-=1}的方式
for (i <- 0 until n) {
fast = fast.next
}
// 快指针和满指针一起走直到fast走到null
while (fast != null) {
slow = slow.next
fast = fast.next
}
// 删除slow的下一个节点
slow.next = slow.next.next
// 返回虚拟头节点的下一个
dummy.next
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -400,6 +400,27 @@ bool isValid(char * s){
return !stackTop;
}
```
Scala:
```scala
object Solution {
import scala.collection.mutable
def isValid(s: String): Boolean = {
if(s.length % 2 != 0) return false // 如果字符串长度是奇数直接返回false
val stack = mutable.Stack[Char]()
// 循环遍历字符串
for (i <- s.indices) {
val c = s(i)
if (c == '(' || c == '[' || c == '{') stack.push(c)
else if(stack.isEmpty) return false // 如果没有(、[、{则直接返回false
// 以下三种情况不满足则直接返回false
else if(c==')' && stack.pop() != '(') return false
else if(c==']' && stack.pop() != '[') return false
else if(c=='}' && stack.pop() != '{') return false
}
// 如果为空则正确匹配,否则还有余孽就不匹配
stack.isEmpty
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -311,7 +311,29 @@ func swapPairs(_ head: ListNode?) -> ListNode? {
return dummyHead.next
}
```
Scala:
```scala
// 虚拟头节点
object Solution {
def swapPairs(head: ListNode): ListNode = {
var dummy = new ListNode(0, head) // 虚拟头节点
var pre = dummy
var cur = head
// 当pre的下一个和下下个都不为空才进行两两转换
while (pre.next != null && pre.next.next != null) {
var tmp: ListNode = cur.next.next // 缓存下一次要进行转换的第一个节点
pre.next = cur.next // 步骤一
cur.next.next = cur // 步骤二
cur.next = tmp // 步骤三
// 下面是准备下一轮的交换
pre = cur
cur = tmp
}
// 最终返回dummy虚拟头节点的下一个return可以省略
dummy.next
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -28,6 +28,8 @@
## 思路
[本题B站视频讲解](https://www.bilibili.com/video/BV12A4y1Z7LP)
有的同学可能说了,多余的元素,删掉不就得了。
**要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。**
@ -75,13 +77,23 @@ public:
双指针法(快慢指针法): **通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。**
定义快慢指针
* 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
* 慢指针:指向更新 新数组下标的位置
很多同学这道题目做的很懵,就是不理解 快慢指针究竟都是什么含义,所以一定要明确含义,后面的思路就更容易理解了。
删除过程如下:
![27.移除元素-双指针法](https://tva1.sinaimg.cn/large/008eGmZEly1gntrds6r59g30du09mnpd.gif)
很多同学不了解
**双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。**
后序都会一一介绍到,本题代码如下:
都会一一介绍到,本题代码如下:
```CPP
// 时间复杂度O(n)
@ -104,8 +116,6 @@ public:
* 时间复杂度O(n)
* 空间复杂度O(1)
旧文链接:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)
```CPP
/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
@ -329,5 +339,34 @@ int removeElement(int* nums, int numsSize, int val){
}
```
Kotlin:
```kotlin
fun removeElement(nums: IntArray, `val`: Int): Int {
var slowIndex = 0 // 初始化慢指针
for (fastIndex in nums.indices) {
if (nums[fastIndex] != `val`) nums[slowIndex++] = nums[fastIndex] // 在慢指针所在位置存储未被删除的元素
}
return slowIndex
}
```
Scala:
```scala
object Solution {
def removeElement(nums: Array[Int], `val`: Int): Int = {
var slow = 0
for (fast <- 0 until nums.length) {
if (`val` != nums(fast)) {
nums(slow) = nums(fast)
slow += 1
}
}
slow
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -1166,5 +1166,80 @@ func strStr(_ haystack: String, _ needle: String) -> Int {
```
PHP
> 前缀表统一减一
```php
function strStr($haystack, $needle) {
if (strlen($needle) == 0) return 0;
$next= [];
$this->getNext($next,$needle);
$j = -1;
for ($i = 0;$i < strlen($haystack); $i++) { // 注意i就从0开始
while($j >= 0 && $haystack[$i] != $needle[$j + 1]) {
$j = $next[$j];
}
if ($haystack[$i] == $needle[$j + 1]) {
$j++;
}
if ($j == (strlen($needle) - 1) ) {
return ($i - strlen($needle) + 1);
}
}
return -1;
}
function getNext(&$next, $s){
$j = -1;
$next[0] = $j;
for($i = 1; $i < strlen($s); $i++) { // 注意i从1开始
while ($j >= 0 && $s[$i] != $s[$j + 1]) {
$j = $next[$j];
}
if ($s[$i] == $s[$j + 1]) {
$j++;
}
$next[$i] = $j;
}
}
```
> 前缀表统一不减一
```php
function strStr($haystack, $needle) {
if (strlen($needle) == 0) return 0;
$next= [];
$this->getNext($next,$needle);
$j = 0;
for ($i = 0;$i < strlen($haystack); $i++) { // 注意i就从0开始
while($j > 0 && $haystack[$i] != $needle[$j]) {
$j = $next[$j-1];
}
if ($haystack[$i] == $needle[$j]) {
$j++;
}
if ($j == strlen($needle)) {
return ($i - strlen($needle) + 1);
}
}
return -1;
}
function getNext(&$next, $s){
$j = 0;
$next[0] = $j;
for($i = 1; $i < strlen($s); $i++) { // 注意i从1开始
while ($j > 0 && $s[$i] != $s[$j]) {
$j = $next[$j-1];
}
if ($s[$i] == $s[$j]) {
$j++;
}
$next[$i] = $j;
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -480,7 +480,52 @@ var searchRange = function(nums, target) {
return [-1, -1];
};
```
### Scala
```scala
object Solution {
def searchRange(nums: Array[Int], target: Int): Array[Int] = {
var left = getLeftBorder(nums, target)
var right = getRightBorder(nums, target)
if (left == -2 || right == -2) return Array(-1, -1)
if (right - left > 1) return Array(left + 1, right - 1)
Array(-1, -1)
}
// 寻找左边界
def getLeftBorder(nums: Array[Int], target: Int): Int = {
var leftBorder = -2
var left = 0
var right = nums.length - 1
while (left <= right) {
var mid = left + (right - left) / 2
if (nums(mid) >= target) {
right = mid - 1
leftBorder = right
} else {
left = mid + 1
}
}
leftBorder
}
// 寻找右边界
def getRightBorder(nums: Array[Int], target: Int): Int = {
var rightBorder = -2
var left = 0
var right = nums.length - 1
while (left <= right) {
var mid = left + (right - left) / 2
if (nums(mid) <= target) {
left = mid + 1
rightBorder = left
} else {
right = mid - 1
}
}
rightBorder
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -73,8 +73,8 @@ public:
};
```
* 时间复杂度:$O(n)$
* 空间复杂度:$O(1)$
* 时间复杂度O(n)
* 空间复杂度O(1)
效率如下:
@ -135,14 +135,14 @@ public:
// 目标值在数组所有元素之前 [0, -1]
// 目标值等于数组中某一个元素 return middle;
// 目标值插入数组中的位置 [left, right]return right + 1
// 目标值在数组所有元素之后的情况 [left, right] return right + 1
// 目标值在数组所有元素之后的情况 [left, right] 因为是右闭区间,所以 return right + 1
return right + 1;
}
};
```
* 时间复杂度:$O(\log n)$
* 时间复杂度:$O(1)$
* 时间复杂度O(log n)
* 时间复杂度:O(1)
效率如下:
![35_搜索插入位置2](https://img-blog.csdnimg.cn/2020121623272877.png)
@ -178,7 +178,7 @@ public:
// 目标值在数组所有元素之前 [0,0)
// 目标值等于数组中某一个元素 return middle
// 目标值插入数组中的位置 [left, right) return right 即可
// 目标值在数组所有元素之后的情况 [left, right)return right 即可
// 目标值在数组所有元素之后的情况 [left, right)因为是右开区间,所以 return right
return right;
}
};
@ -316,8 +316,52 @@ func searchInsert(_ nums: [Int], _ target: Int) -> Int {
return right + 1
}
```
### Scala
```scala
object Solution {
def searchInsert(nums: Array[Int], target: Int): Int = {
var left = 0
var right = nums.length - 1
while (left <= right) {
var mid = left + (right - left) / 2
if (target == nums(mid)) {
return mid
} else if (target > nums(mid)) {
left = mid + 1
} else {
right = mid - 1
}
}
right + 1
}
}
```
### PHP
```php
// 二分法(1)[左闭右闭]
function searchInsert($nums, $target)
{
$n = count($nums);
$l = 0;
$r = $n - 1;
while ($l <= $r) {
$mid = floor(($l + $r) / 2);
if ($nums[$mid] > $target) {
// 下次搜索在左区间:[$l,$mid-1]
$r = $mid - 1;
} else if ($nums[$mid] < $target) {
// 下次搜索在右区间:[$mid+1,$r]
$l = $mid + 1;
} else {
// 命中返回
return $mid;
}
}
return $r + 1;
}
```
-----------------------

View File

@ -370,18 +370,17 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int)
```js
var combinationSum = function(candidates, target) {
const res = [], path = [];
candidates.sort(); // 排序
candidates.sort((a,b)=>a-b); // 排序
backtracking(0, 0);
return res;
function backtracking(j, sum) {
if (sum > target) return;
if (sum === target) {
res.push(Array.from(path));
return;
}
for(let i = j; i < candidates.length; i++ ) {
const n = candidates[i];
if(n > target - sum) continue;
if(n > target - sum) break;
path.push(n);
sum += n;
backtracking(i, sum);

View File

@ -508,22 +508,27 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int)
*/
var combinationSum2 = function(candidates, target) {
const res = []; path = [], len = candidates.length;
candidates.sort();
candidates.sort((a,b)=>a-b);
backtracking(0, 0);
return res;
function backtracking(sum, i) {
if (sum > target) return;
if (sum === target) {
res.push(Array.from(path));
return;
}
let f = -1;
for(let j = i; j < len; j++) {
const n = candidates[j];
if(n > target - sum || n === f) continue;
if(j > i && candidates[j] === candidates[j-1]){
//若当前元素和前一个元素相等
//则本次循环结束,防止出现重复组合
continue;
}
//如果当前元素值大于目标值-总和的值
//由于数组已排序,那么该元素之后的元素必定不满足条件
//直接终止当前层的递归
if(n > target - sum) break;
path.push(n);
sum += n;
f = n;
backtracking(sum, j + 1);
path.pop();
sum -= n;

View File

@ -744,6 +744,91 @@ var trap = function(height) {
};
```
### TypeScript
双指针法:
```typescript
function trap(height: number[]): number {
const length: number = height.length;
let resVal: number = 0;
for (let i = 0; i < length; i++) {
let leftMaxHeight: number = height[i],
rightMaxHeight: number = height[i];
let leftIndex: number = i - 1,
rightIndex: number = i + 1;
while (leftIndex >= 0) {
if (height[leftIndex] > leftMaxHeight)
leftMaxHeight = height[leftIndex];
leftIndex--;
}
while (rightIndex < length) {
if (height[rightIndex] > rightMaxHeight)
rightMaxHeight = height[rightIndex];
rightIndex++;
}
resVal += Math.min(leftMaxHeight, rightMaxHeight) - height[i];
}
return resVal;
};
```
动态规划:
```typescript
function trap(height: number[]): number {
const length: number = height.length;
const leftMaxHeightDp: number[] = [],
rightMaxHeightDp: number[] = [];
leftMaxHeightDp[0] = height[0];
rightMaxHeightDp[length - 1] = height[length - 1];
for (let i = 1; i < length; i++) {
leftMaxHeightDp[i] = Math.max(height[i], leftMaxHeightDp[i - 1]);
}
for (let i = length - 2; i >= 0; i--) {
rightMaxHeightDp[i] = Math.max(height[i], rightMaxHeightDp[i + 1]);
}
let resVal: number = 0;
for (let i = 0; i < length; i++) {
resVal += Math.min(leftMaxHeightDp[i], rightMaxHeightDp[i]) - height[i];
}
return resVal;
};
```
单调栈:
```typescript
function trap(height: number[]): number {
const length: number = height.length;
const stack: number[] = [];
stack.push(0);
let resVal: number = 0;
for (let i = 1; i < length; i++) {
let top = stack[stack.length - 1];
if (height[top] > height[i]) {
stack.push(i);
} else if (height[top] === height[i]) {
stack.pop();
stack.push(i);
} else {
while (stack.length > 0 && height[top] < height[i]) {
let mid = stack.pop();
if (stack.length > 0) {
let left = stack[stack.length - 1];
let h = Math.min(height[left], height[i]) - height[mid];
let w = i - left - 1;
resVal += h * w;
top = stack[stack.length - 1];
}
}
stack.push(i);
}
}
return resVal;
};
```
### C:
一种更简便的双指针方法:

View File

@ -217,18 +217,26 @@ class Solution:
### Go
```Go
func jump(nums []int) int {
dp:=make([]int ,len(nums))
dp[0]=0
dp := make([]int, len(nums))
dp[0] = 0//初始第一格跳跃数一定为0
for i:=1;i<len(nums);i++{
dp[i]=i
for j:=0;j<i;j++{
if nums[j]+j>i{
dp[i]=min(dp[j]+1,dp[i])
}
}
}
return dp[len(nums)-1]
for i := 1; i < len(nums); i++ {
dp[i] = i
for j := 0; j < i; j++ {
if nums[j] + j >= i {//nums[j]为起点,j为往右跳的覆盖范围,这行表示从j能跳到i
dp[i] = min(dp[j] + 1, dp[i])//更新最小能到i的跳跃次数
}
}
}
return dp[len(nums)-1]
}
func min(a, b int) int {
if a < b {
return a
} else {
return b
}
}
```

View File

@ -341,7 +341,7 @@ function permute(nums: number[]): number[][] {
return resArr;
function backTracking(nums: number[], route: number[]): void {
if (route.length === nums.length) {
resArr.push(route.slice());
resArr.push([...route]);
return;
}
let tempVal: number;

View File

@ -268,7 +268,7 @@ var permuteUnique = function (nums) {
function backtracing( used) {
if (path.length === nums.length) {
result.push(path.slice())
result.push([...path])
return
}
for (let i = 0; i < nums.length; i++) {
@ -303,7 +303,7 @@ function permuteUnique(nums: number[]): number[][] {
return resArr;
function backTracking(nums: number[], route: number[]): void {
if (route.length === nums.length) {
resArr.push(route.slice());
resArr.push([...route]);
return;
}
for (let i = 0, length = nums.length; i < length; i++) {

View File

@ -212,6 +212,20 @@ func maxSubArray(nums []int) int {
}
```
### Rust
```rust
pub fn max_sub_array(nums: Vec<i32>) -> i32 {
let mut max_sum = i32::MIN;
let mut curr = 0;
for n in nums.iter() {
curr += n;
max_sum = max_sum.max(curr);
curr = curr.max(0);
}
max_sum
}
```
### Javascript:
```Javascript
var maxSubArray = function(nums) {

View File

@ -186,6 +186,24 @@ const maxSubArray = nums => {
};
```
TypeScript
```typescript
function maxSubArray(nums: number[]): number {
/**
dp[i]以nums[i]结尾的最大和
*/
const dp: number[] = []
dp[0] = nums[0];
let resMax: number = 0;
for (let i = 1; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
resMax = Math.max(resMax, dp[i]);
}
return resMax;
};
```
-----------------------

View File

@ -96,7 +96,7 @@ public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
if (intervals.size() == 0) return result;
// 排序的参数使用了lamda表达式
// 排序的参数使用了lambda表达式
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});
result.push_back(intervals[0]);
@ -112,8 +112,8 @@ public:
};
```
* 时间复杂度:$O(n\log n)$ ,有一个快排
* 空间复杂度:$O(1)$我没有算result数组返回值所需容器占的空间
* 时间复杂度O(nlog n) ,有一个快排
* 空间复杂度:O(n),有一个快排,最差情况(倒序)时需要n次递归调用。因此确实需要O(n)的栈空间
## 总结

View File

@ -130,57 +130,37 @@ Java
```Java
class Solution {
public int[][] generateMatrix(int n) {
int loop = 0; // 控制循环次数
int[][] res = new int[n][n];
int start = 0; // 每次循环的开始点(start, start)
int count = 1; // 定义填充数字
int i, j;
// 循环次数
int loop = n / 2;
// 定义每次循环起始位置
int startX = 0;
int startY = 0;
// 定义偏移量
int offset = 1;
// 定义填充数字
int count = 1;
// 定义中间位置
int mid = n / 2;
while (loop > 0) {
int i = startX;
int j = startY;
while (loop++ < n / 2) { // 判断边界后loop从1开始
// 模拟上侧从左到右
for (; j<startY + n -offset; ++j) {
res[startX][j] = count++;
for (j = start; j < n - loop; j++) {
res[start][j] = count++;
}
// 模拟右侧从上到下
for (; i<startX + n -offset; ++i) {
for (i = start; i < n - loop; i++) {
res[i][j] = count++;
}
// 模拟下侧从右到左
for (; j > startY; j--) {
for (; j >= loop; j--) {
res[i][j] = count++;
}
// 模拟左侧从下到上
for (; i > startX; i--) {
for (; i >= loop; i--) {
res[i][j] = count++;
}
loop--;
startX += 1;
startY += 1;
offset += 2;
start++;
}
if (n % 2 == 1) {
res[mid][mid] = count;
res[start][start] = count;
}
return res;
@ -564,6 +544,57 @@ int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
return ans;
}
```
Scala:
```scala
object Solution {
def generateMatrix(n: Int): Array[Array[Int]] = {
var res = Array.ofDim[Int](n, n) // 定义一个n*n的二维矩阵
var num = 1 // 标志当前到了哪个数字
var i = 0 // 横坐标
var j = 0 // 竖坐标
while (num <= n * n) {
// 向右当j不越界并且下一个要填的数字是空白时
while (j < n && res(i)(j) == 0) {
res(i)(j) = num // 当前坐标等于num
num += 1 // num++
j += 1 // 竖坐标+1
}
i += 1 // 下移一行
j -= 1 // 左移一列
// 剩下的都同上
// 向下
while (i < n && res(i)(j) == 0) {
res(i)(j) = num
num += 1
i += 1
}
i -= 1
j -= 1
// 向左
while (j >= 0 && res(i)(j) == 0) {
res(i)(j) = num
num += 1
j -= 1
}
i -= 1
j += 1
// 向上
while (i >= 0 && res(i)(j) == 0) {
res(i)(j) = num
num += 1
i -= 1
}
i += 1
j += 1
}
res
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -347,7 +347,35 @@ var uniquePaths = function(m, n) {
};
```
### TypeScript
```typescript
function uniquePaths(m: number, n: number): number {
/**
dp[i][j]: 到达(i, j)的路径数
dp[0][*]: 1;
dp[*][0]: 1;
...
dp[i][j]: dp[i - 1][j] + dp[i][j - 1];
*/
const dp: number[][] = new Array(m).fill(0).map(_ => []);
for (let i = 0; i < m; i++) {
dp[i][0] = 1;
}
for (let i = 0; i < n; i++) {
dp[0][i] = 1;
}
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
};
```
### C
```c
//初始化dp数组
int **initDP(int m, int n) {

View File

@ -66,7 +66,7 @@ dp[i][j] 表示从0 0出发到(i, j) 有dp[i][j]条不同的路
所以代码为:
```
```cpp
if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候再推导dp[i][j]
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
@ -76,7 +76,7 @@ if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候再推导dp[i
在[62.不同路径](https://programmercarl.com/0062.不同路径.html)不同路径中我们给出如下的初始化:
```
```cpp
vector<vector<int>> dp(m, vector<int>(n, 0)); // 初始值为0
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
@ -138,6 +138,8 @@ public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) //如果在起点或终点出现了障碍直接返回0
return 0;
vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
@ -352,7 +354,38 @@ var uniquePathsWithObstacles = function(obstacleGrid) {
};
```
C
### TypeScript
```typescript
function uniquePathsWithObstacles(obstacleGrid: number[][]): number {
/**
dp[i][j]: 到达(i, j)的路径数
dp[0][*]: 用u表示第一个障碍物下标则u之前为1u之后含u为0
dp[*][0]: 同上
...
dp[i][j]: obstacleGrid[i][j] === 1 ? 0 : dp[i-1][j] + dp[i][j-1];
*/
const m: number = obstacleGrid.length;
const n: number = obstacleGrid[0].length;
const dp: number[][] = new Array(m).fill(0).map(_ => new Array(n).fill(0));
for (let i = 0; i < m && obstacleGrid[i][0] === 0; i++) {
dp[i][0] = 1;
}
for (let i = 0; i < n && obstacleGrid[0][i] === 0; i++) {
dp[0][i] = 1;
}
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
if (obstacleGrid[i][j] === 1) continue;
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
};
```
### C
```c
//初始化dp数组
int **initDP(int m, int n, int** obstacleGrid) {

View File

@ -308,7 +308,58 @@ var climbStairs = function(n) {
};
```
TypeScript
> 爬2阶
```typescript
function climbStairs(n: number): number {
/**
dp[i]: i阶楼梯的方法种数
dp[1]: 1;
dp[2]: 2;
...
dp[i]: dp[i - 1] + dp[i - 2];
*/
const dp: number[] = [];
dp[1] = 1;
dp[2] = 2;
for (let i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
};
```
> 爬m阶
```typescript
function climbStairs(n: number): number {
/**
一次可以爬m阶
dp[i]: i阶楼梯的方法种数
dp[1]: 1;
dp[2]: 2;
dp[3]: dp[2] + dp[1];
...
dp[i]: dp[i - 1] + dp[i - 2] + ... + dp[max(i - m, 1)]; 从i-1加到max(i-m, 1)
*/
const m: number = 2; // 本题m为2
const dp: number[] = new Array(n + 1).fill(0);
dp[1] = 1;
dp[2] = 2;
for (let i = 3; i <= n; i++) {
const end: number = Math.max(i - m, 1);
for (let j = i - 1; j >= end; j--) {
dp[i] += dp[j];
}
}
return dp[n];
};
```
### C
```c
int climbStairs(int n){
//若n<=2返回n

View File

@ -199,6 +199,28 @@ var climbStairs = function(n) {
};
```
TypeScript
```typescript
function climbStairs(n: number): number {
const m: number = 2; // 本题m为2
const dp: number[] = new Array(n + 1).fill(0);
dp[0] = 1;
// 遍历背包
for (let i = 1; i <= n; i++) {
// 遍历物品
for (let j = 1; j <= m; j++) {
if (j <= i) {
dp[i] += dp[i - j];
}
}
}
return dp[n];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -327,5 +327,42 @@ const minDistance = (word1, word2) => {
};
```
TypeScript
```typescript
function minDistance(word1: string, word2: string): number {
/**
dp[i][j]: word1前i个字符word2前j个字符最少操作数
dp[0][0]=0表示word1前0个字符为'', word2前0个字符为''
*/
const length1: number = word1.length,
length2: number = word2.length;
const dp: number[][] = new Array(length1 + 1).fill(0)
.map(_ => new Array(length2 + 1).fill(0));
for (let i = 0; i <= length1; i++) {
dp[i][0] = i;
}
for (let i = 0; i <= length2; i++) {
dp[0][i] = i;
}
for (let i = 1; i <= length1; i++) {
for (let j = 1; j <= length2; j++) {
if (word1[i - 1] === word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(
dp[i - 1][j],
dp[i][j - 1],
dp[i - 1][j - 1]
) + 1;
}
}
}
return dp[length1][length2];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -27,7 +27,7 @@
也可以直接看我的B站视频[带你学透回溯算法-组合问题对应力扣题目77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv#reply3733925949)
# 思路
## 思路
本题这是回溯法的经典题目。
@ -232,7 +232,7 @@ void backtracking(参数) {
**对比一下本题的代码,是不是发现有点像!** 所以有了这个模板,就有解题的大体方向,不至于毫无头绪。
# 总结
## 总结
组合问题是回溯法解决的经典问题我们开始的时候给大家列举一个很形象的例子就是n为100k为50的话直接想法就需要50层for循环。
@ -242,7 +242,7 @@ void backtracking(参数) {
接着用回溯法三部曲,逐步分析了函数参数、终止条件和单层搜索的过程。
# 剪枝优化
## 剪枝优化
我们说过,回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的。
@ -324,7 +324,7 @@ public:
};
```
# 剪枝总结
## 剪枝总结
本篇我们准对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。
@ -334,10 +334,10 @@ public:
# 其他语言版本
## 其他语言版本
## Java
### Java
```java
class Solution {
List<List<Integer>> result = new ArrayList<>();
@ -366,6 +366,8 @@ class Solution {
}
```
### Python
Python2:
```python
class Solution(object):
@ -395,7 +397,6 @@ class Solution(object):
return result
```
## Python
```python
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
@ -432,7 +433,7 @@ class Solution:
```
## javascript
### javascript
剪枝:
```javascript
@ -456,7 +457,7 @@ const combineHelper = (n, k, startIndex) => {
}
```
## TypeScript
### TypeScript
```typescript
function combine(n: number, k: number): number[][] {
@ -479,7 +480,7 @@ function combine(n: number, k: number): number[][] {
## Go
### Go
```Go
var res [][]int
func combine(n int, k int) [][]int {
@ -534,7 +535,7 @@ func backtrack(n,k,start int,track []int){
}
```
## C
### C
```c
int* path;
int pathTop;
@ -642,7 +643,7 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
}
```
## Swift
### Swift
```swift
func combine(_ n: Int, _ k: Int) -> [[Int]] {

View File

@ -260,7 +260,7 @@ var subsets = function(nums) {
let result = []
let path = []
function backtracking(startIndex) {
result.push(path.slice())
result.push([...path])
for(let i = startIndex; i < nums.length; i++) {
path.push(nums[i])
backtracking(i + 1)
@ -280,7 +280,7 @@ function subsets(nums: number[]): number[][] {
backTracking(nums, 0, []);
return resArr;
function backTracking(nums: number[], startIndex: number, route: number[]): void {
resArr.push(route.slice());
resArr.push([...route]);
let length = nums.length;
if (startIndex === length) return;
for (let i = startIndex; i < length; i++) {

View File

@ -486,5 +486,95 @@ var largestRectangleArea = function(heights) {
return maxArea;
};
```
TypeScript
> 双指针法(会超时):
```typescript
function largestRectangleArea(heights: number[]): number {
let resMax: number = 0;
for (let i = 0, length = heights.length; i < length; i++) {
// 左开右开
let left: number = i - 1,
right: number = i + 1;
while (left >= 0 && heights[left] >= heights[i]) {
left--;
}
while (right < length && heights[right] >= heights[i]) {
right++;
}
resMax = Math.max(resMax, heights[i] * (right - left - 1));
}
return resMax;
};
```
> 动态规划预处理:
```typescript
function largestRectangleArea(heights: number[]): number {
const length: number = heights.length;
const leftHeightDp: number[] = [],
rightHeightDp: number[] = [];
leftHeightDp[0] = -1;
rightHeightDp[length - 1] = length;
for (let i = 1; i < length; i++) {
let j = i - 1;
while (j >= 0 && heights[i] <= heights[j]) {
j = leftHeightDp[j];
}
leftHeightDp[i] = j;
}
for (let i = length - 2; i >= 0; i--) {
let j = i + 1;
while (j < length && heights[i] <= heights[j]) {
j = rightHeightDp[j];
}
rightHeightDp[i] = j;
}
let resMax: number = 0;
for (let i = 0; i < length; i++) {
let area = heights[i] * (rightHeightDp[i] - leftHeightDp[i] - 1);
resMax = Math.max(resMax, area);
}
return resMax;
};
```
> 单调栈:
```typescript
function largestRectangleArea(heights: number[]): number {
heights.push(0);
const length: number = heights.length;
// 栈底->栈顶:严格单调递增
const stack: number[] = [];
stack.push(0);
let resMax: number = 0;
for (let i = 1; i < length; i++) {
let top = stack[stack.length - 1];
if (heights[top] < heights[i]) {
stack.push(i);
} else if (heights[top] === heights[i]) {
stack.pop();
stack.push(i);
} else {
while (stack.length > 0 && heights[top] > heights[i]) {
let mid = stack.pop();
let left = stack.length > 0 ? stack[stack.length - 1] : -1;
let w = i - left - 1;
let h = heights[mid];
resMax = Math.max(resMax, w * h);
top = stack[stack.length - 1];
}
stack.push(i);
}
}
return resMax;
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -299,7 +299,7 @@ var subsetsWithDup = function(nums) {
return a - b
})
function backtracing(startIndex, sortNums) {
result.push(path.slice(0))
result.push([...path])
if(startIndex > nums.length - 1) {
return
}
@ -327,7 +327,7 @@ function subsetsWithDup(nums: number[]): number[][] {
backTraking(nums, 0, []);
return resArr;
function backTraking(nums: number[], startIndex: number, route: number[]): void {
resArr.push(route.slice());
resArr.push([...route]);
let length: number = nums.length;
if (startIndex === length) return;
for (let i = startIndex; i < length; i++) {

View File

@ -444,7 +444,7 @@ var restoreIpAddresses = function(s) {
return;
}
for(let j = i; j < s.length; j++) {
const str = s.substr(i, j - i + 1);
const str = s.slice(i, j + 1);
if(str.length > 3 || +str > 255) break;
if(str.length > 1 && str[0] === "0") break;
path.push(str);

View File

@ -227,7 +227,33 @@ const numTrees =(n) => {
};
```
C:
TypeScript
```typescript
function numTrees(n: number): number {
/**
dp[i]: i个节点对应的种树
dp[0]: -1; 无意义;
dp[1]: 1;
...
dp[i]: 2 * dp[i - 1] +
(dp[1] * dp[i - 2] + dp[2] * dp[i - 3] + ... + dp[i - 2] * dp[1]); 从1加到i-2
*/
const dp: number[] = [];
dp[0] = -1; // 表示无意义
dp[1] = 1;
for (let i = 2; i <= n; i++) {
dp[i] = 2 * dp[i - 1];
for (let j = 1, end = i - 1; j < end; j++) {
dp[i] += dp[j] * dp[end - j];
}
}
return dp[n];
};
```
### C
```c
//开辟dp数组
int *initDP(int n) {

View File

@ -238,7 +238,7 @@ public:
};
```
# 总结
## 总结
这次我们又深度剖析了一道二叉树的“简单题”大家会发现真正的把题目搞清楚其实并不简单leetcode上accept了和真正掌握了还是有距离的。
@ -248,7 +248,7 @@ public:
如果已经做过这道题目的同学,读完文章可以再去看看这道题目,思考一下,会有不一样的发现!
# 相关题目推荐
## 相关题目推荐
这两道题目基本和本题是一样的只要稍加修改就可以AC。
@ -725,5 +725,25 @@ func isSymmetric3(_ root: TreeNode?) -> Bool {
}
```
## Scala
递归:
```scala
object Solution {
def isSymmetric(root: TreeNode): Boolean = {
if (root == null) return true // 如果等于空直接返回true
def compare(left: TreeNode, right: TreeNode): Boolean = {
if (left == null && right == null) return true // 如果左右都为空则为true
if (left == null && right != null) return false // 如果左空右不空不对称返回false
if (left != null && right == null) return false // 如果左不空右空不对称返回false
// 如果左右的值相等,并且往下递归
left.value == right.value && compare(left.left, right.right) && compare(left.right, right.left)
}
// 分别比较左子树和右子树
compare(root.left, root.right)
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -82,6 +82,26 @@ public:
}
};
```
```CPP
# 递归法
class Solution {
public:
void order(TreeNode* cur, vector<vector<int>>& result, int depth)
{
if (cur == nullptr) return;
if (result.size() == depth) result.push_back(vector<int>());
result[depth].push_back(cur->val);
order(cur->left, result, depth + 1);
order(cur->right, result, depth + 1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
int depth = 0;
order(root, result, depth);
return result;
}
};
```
python3代码
@ -298,6 +318,61 @@ func levelOrder(_ root: TreeNode?) -> [[Int]] {
return result
}
```
Scala:
```scala
// 102.二叉树的层序遍历
object Solution {
import scala.collection.mutable
def levelOrder(root: TreeNode): List[List[Int]] = {
val res = mutable.ListBuffer[List[Int]]()
if (root == null) return res.toList
val queue = mutable.Queue[TreeNode]() // 声明一个队列
queue.enqueue(root) // 把根节点加入queue
while (!queue.isEmpty) {
val tmp = mutable.ListBuffer[Int]()
val len = queue.size // 求出len的长度
for (i <- 0 until len) { // 从0到当前队列长度的所有节点都加入到结果集
val curNode = queue.dequeue()
tmp.append(curNode.value)
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
res.append(tmp.toList)
}
res.toList
}
}
```
Rust:
```rust
pub fn level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
let mut ans = Vec::new();
let mut stack = Vec::new();
if root.is_none(){
return ans;
}
stack.push(root.unwrap());
while stack.is_empty()!= true{
let num = stack.len();
let mut level = Vec::new();
for _i in 0..num{
let tmp = stack.remove(0);
level.push(tmp.borrow_mut().val);
if tmp.borrow_mut().left.is_some(){
stack.push(tmp.borrow_mut().left.take().unwrap());
}
if tmp.borrow_mut().right.is_some(){
stack.push(tmp.borrow_mut().right.take().unwrap());
}
}
ans.push(level);
}
ans
}
```
**此时我们就掌握了二叉树的层序遍历了,那么如下九道力扣上的题目,只需要修改模板的两三行代码(不能再多了),便可打倒!**
@ -528,6 +603,61 @@ func levelOrderBottom(_ root: TreeNode?) -> [[Int]] {
}
```
Scala:
```scala
// 107.二叉树的层次遍历II
object Solution {
import scala.collection.mutable
def levelOrderBottom(root: TreeNode): List[List[Int]] = {
val res = mutable.ListBuffer[List[Int]]()
if (root == null) return res.toList
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
val tmp = mutable.ListBuffer[Int]()
val len = queue.size
for (i <- 0 until len) {
val curNode = queue.dequeue()
tmp.append(curNode.value)
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
res.append(tmp.toList)
}
// 最后翻转一下
res.reverse.toList
}
Rust:
```rust
pub fn level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
let mut ans = Vec::new();
let mut stack = Vec::new();
if root.is_none(){
return ans;
}
stack.push(root.unwrap());
while stack.is_empty()!= true{
let num = stack.len();
let mut level = Vec::new();
for _i in 0..num{
let tmp = stack.remove(0);
level.push(tmp.borrow_mut().val);
if tmp.borrow_mut().left.is_some(){
stack.push(tmp.borrow_mut().left.take().unwrap());
}
if tmp.borrow_mut().right.is_some(){
stack.push(tmp.borrow_mut().right.take().unwrap());
}
}
ans.push(level);
}
ans
}
```
# 199.二叉树的右视图
[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-right-side-view/)
@ -750,6 +880,31 @@ func rightSideView(_ root: TreeNode?) -> [Int] {
}
```
Scala:
```scala
// 199.二叉树的右视图
object Solution {
import scala.collection.mutable
def rightSideView(root: TreeNode): List[Int] = {
val res = mutable.ListBuffer[Int]()
if (root == null) return res.toList
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
val len = queue.size
var curNode: TreeNode = null
for (i <- 0 until len) {
curNode = queue.dequeue()
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
res.append(curNode.value) // 把最后一个节点的值加入解集
}
res.toList // 最后需要把res转换为Listreturn关键字可以省略
}
}
```
# 637.二叉树的层平均值
[力扣题目链接](https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/)
@ -981,6 +1136,30 @@ func averageOfLevels(_ root: TreeNode?) -> [Double] {
return result
}
```
Scala:
```scala
// 637.二叉树的层平均值
object Solution {
import scala.collection.mutable
def averageOfLevels(root: TreeNode): Array[Double] = {
val res = mutable.ArrayBuffer[Double]()
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
var sum = 0.0
var len = queue.size
for (i <- 0 until len) {
var curNode = queue.dequeue()
sum += curNode.value // 累加该层的值
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
res.append(sum / len) // 平均值即为sum/len
}
res.toArray // 最后需要转换为Arrayreturn关键字可以省略
}
}
```
# 429.N叉树的层序遍历
@ -1225,6 +1404,34 @@ func levelOrder(_ root: Node?) -> [[Int]] {
}
```
Scala:
```scala
// 429.N叉树的层序遍历
object Solution {
import scala.collection.mutable
def levelOrder(root: Node): List[List[Int]] = {
val res = mutable.ListBuffer[List[Int]]()
if (root == null) return res.toList
val queue = mutable.Queue[Node]()
queue.enqueue(root) // 根节点入队
while (!queue.isEmpty) {
val tmp = mutable.ListBuffer[Int]() // 存储每层节点
val len = queue.size
for (i <- 0 until len) {
val curNode = queue.dequeue()
tmp.append(curNode.value) // 将该节点的值加入tmp
// 循环遍历该节点的子节点,加入队列
for (child <- curNode.children) {
queue.enqueue(child)
}
}
res.append(tmp.toList) // 将该层的节点放到结果集
}
res.toList
}
}
```
# 515.在每个树行中找最大值
[力扣题目链接](https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/)
@ -1433,6 +1640,32 @@ func largestValues(_ root: TreeNode?) -> [Int] {
}
```
Scala:
```scala
// 515.在每个树行中找最大值
object Solution {
import scala.collection.mutable
def largestValues(root: TreeNode): List[Int] = {
val res = mutable.ListBuffer[Int]()
if (root == null) return res.toList
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
var max = Int.MinValue // 初始化max为系统最小值
val len = queue.size
for (i <- 0 until len) {
val curNode = queue.dequeue()
max = math.max(max, curNode.value) // 对比求解最大值
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
res.append(max) // 将最大值放入结果集
}
res.toList
}
}
```
# 116.填充每个节点的下一个右侧节点指针
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
@ -1692,6 +1925,35 @@ func connect(_ root: Node?) -> Node? {
}
```
Scala:
```scala
// 116.填充每个节点的下一个右侧节点指针
object Solution {
import scala.collection.mutable
def connect(root: Node): Node = {
if (root == null) return root
val queue = mutable.Queue[Node]()
queue.enqueue(root)
while (!queue.isEmpty) {
val len = queue.size
val tmp = mutable.ListBuffer[Node]()
for (i <- 0 until len) {
val curNode = queue.dequeue()
tmp.append(curNode)
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
// 处理next指针
for (i <- 0 until tmp.size - 1) {
tmp(i).next = tmp(i + 1)
}
tmp(tmp.size-1).next = null
}
root
}
}
```
# 117.填充每个节点的下一个右侧节点指针II
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/)
@ -1943,6 +2205,35 @@ func connect(_ root: Node?) -> Node? {
}
```
Scala:
```scala
// 117.填充每个节点的下一个右侧节点指针II
object Solution {
import scala.collection.mutable
def connect(root: Node): Node = {
if (root == null) return root
val queue = mutable.Queue[Node]()
queue.enqueue(root)
while (!queue.isEmpty) {
val len = queue.size
val tmp = mutable.ListBuffer[Node]()
for (i <- 0 until len) {
val curNode = queue.dequeue()
tmp.append(curNode)
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
// 处理next指针
for (i <- 0 until tmp.size - 1) {
tmp(i).next = tmp(i + 1)
}
tmp(tmp.size-1).next = null
}
root
}
}
```
# 104.二叉树的最大深度
[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)
@ -2160,6 +2451,30 @@ func maxDepth(_ root: TreeNode?) -> Int {
}
```
Scala:
```scala
// 104.二叉树的最大深度
object Solution {
import scala.collection.mutable
def maxDepth(root: TreeNode): Int = {
if (root == null) return 0
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
var depth = 0
while (!queue.isEmpty) {
val len = queue.length
depth += 1
for (i <- 0 until len) {
val curNode = queue.dequeue()
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
}
depth
}
}
```
# 111.二叉树的最小深度
[力扣题目链接](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)
@ -2379,6 +2694,30 @@ func minDepth(_ root: TreeNode?) -> Int {
}
```
Scala:
```scala
// 111.二叉树的最小深度
object Solution {
import scala.collection.mutable
def minDepth(root: TreeNode): Int = {
if (root == null) return 0
var depth = 0
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
depth += 1
val len = queue.size
for (i <- 0 until len) {
val curNode = queue.dequeue()
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
if (curNode.left == null && curNode.right == null) return depth
}
}
depth
}
}
```
# 总结

View File

@ -192,6 +192,33 @@ public:
};
```
rust:
```rust
impl Solution {
pub fn max_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
if root.is_none(){
return 0;
}
let mut max_depth: i32 = 0;
let mut stack = vec![root.unwrap()];
while !stack.is_empty() {
let num = stack.len();
for _i in 0..num{
let top = stack.remove(0);
if top.borrow_mut().left.is_some(){
stack.push(top.borrow_mut().left.take().unwrap());
}
if top.borrow_mut().right.is_some(){
stack.push(top.borrow_mut().right.take().unwrap());
}
}
max_depth+=1;
}
max_depth
}
```
那么我们可以顺便解决一下n叉树的最大深度问题
# 559.n叉树的最大深度
@ -468,7 +495,7 @@ class solution:
## go
### 104.二叉树的最大深度
```go
/**
* definition for a binary tree node.
@ -521,6 +548,8 @@ func maxdepth(root *treenode) int {
## javascript
### 104.二叉树的最大深度
```javascript
var maxdepth = function(root) {
if (root === null) return 0;
@ -568,6 +597,8 @@ var maxDepth = function(root) {
};
```
### 559.n叉树的最大深度
N叉树的最大深度 递归写法
```js
var maxDepth = function(root) {
@ -600,9 +631,9 @@ var maxDepth = function(root) {
};
```
## TypeScript
## TypeScript
> 二叉树的最大深度:
### 104.二叉树的最大深度
```typescript
// 后续遍历(自下而上)
@ -645,7 +676,7 @@ function maxDepth(root: TreeNode | null): number {
};
```
> N叉树的最大深度
### 559.n叉树的最大深度
```typescript
// 后续遍历(自下而上)
@ -675,6 +706,8 @@ function maxDepth(root: TreeNode | null): number {
## C
### 104.二叉树的最大深度
二叉树最大深度递归
```c
int maxDepth(struct TreeNode* root){
@ -731,7 +764,8 @@ int maxDepth(struct TreeNode* root){
## Swift
>二叉树最大深度
### 104.二叉树的最大深度
```swift
// 递归 - 后序
func maxDepth1(_ root: TreeNode?) -> Int {
@ -770,7 +804,8 @@ func maxDepth(_ root: TreeNode?) -> Int {
}
```
>N叉树最大深度
### 559.n叉树的最大深度
```swift
// 递归
func maxDepth(_ root: Node?) -> Int {
@ -806,5 +841,84 @@ func maxDepth1(_ root: Node?) -> Int {
}
```
## Scala
### 104.二叉树的最大深度
递归法:
```scala
object Solution {
def maxDepth(root: TreeNode): Int = {
def process(curNode: TreeNode): Int = {
if (curNode == null) return 0
// 递归左节点和右节点,返回最大的,最后+1
math.max(process(curNode.left), process(curNode.right)) + 1
}
// 调用递归方法return关键字可以省略
process(root)
}
}
```
迭代法:
```scala
object Solution {
import scala.collection.mutable
def maxDepth(root: TreeNode): Int = {
var depth = 0
if (root == null) return depth
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
val len = queue.size
for (i <- 0 until len) {
val curNode = queue.dequeue()
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
depth += 1 // 只要有层次就+=1
}
depth
}
}
```
### 559.n叉树的最大深度
递归法:
```scala
object Solution {
def maxDepth(root: Node): Int = {
if (root == null) return 0
var depth = 0
for (node <- root.children) {
depth = math.max(depth, maxDepth(node))
}
depth + 1
}
}
```
迭代法: (层序遍历)
```scala
object Solution {
import scala.collection.mutable
def maxDepth(root: Node): Int = {
if (root == null) return 0
var depth = 0
val queue = mutable.Queue[Node]()
queue.enqueue(root)
while (!queue.isEmpty) {
val len = queue.size
depth += 1
for (i <- 0 until len) {
val curNode = queue.dequeue()
for (node <- curNode.children) queue.enqueue(node)
}
}
depth
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -208,7 +208,7 @@ int getHeight(TreeNode* node) {
```CPP
class Solution {
public:
// 返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1
// 返回以该节点为根节点的二叉树的高度,如果不是平衡二叉树了则返回-1
int getHeight(TreeNode* node) {
if (node == NULL) {
return 0;

View File

@ -488,5 +488,110 @@ func minDepth(_ root: TreeNode?) -> Int {
}
```
## Scala
递归法:
```scala
object Solution {
def minDepth(root: TreeNode): Int = {
if (root == null) return 0
if (root.left == null && root.right != null) return 1 + minDepth(root.right)
if (root.left != null && root.right == null) return 1 + minDepth(root.left)
// 如果两侧都不为空则取最小值return关键字可以省略
1 + math.min(minDepth(root.left), minDepth(root.right))
}
}
```
迭代法:
```scala
object Solution {
import scala.collection.mutable
def minDepth(root: TreeNode): Int = {
if (root == null) return 0
var depth = 0
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
depth += 1
val len = queue.size
for (i <- 0 until len) {
val curNode = queue.dequeue()
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
if (curNode.left == null && curNode.right == null) return depth
}
}
depth
}
}
```
rust:
```rust
impl Solution {
pub fn min_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
return Solution::bfs(root)
}
// 递归
pub fn dfs(node: Option<Rc<RefCell<TreeNode>>>) -> i32{
if node.is_none(){
return 0;
}
let parent = node.unwrap();
let left_child = parent.borrow_mut().left.take();
let right_child = parent.borrow_mut().right.take();
if left_child.is_none() && right_child.is_none(){
return 1;
}
let mut min_depth = i32::MAX;
if left_child.is_some(){
let left_depth = Solution::dfs(left_child);
if left_depth <= min_depth{
min_depth = left_depth
}
}
if right_child.is_some(){
let right_depth = Solution::dfs(right_child);
if right_depth <= min_depth{
min_depth = right_depth
}
}
min_depth + 1
}
// 迭代
pub fn bfs(node: Option<Rc<RefCell<TreeNode>>>) -> i32{
let mut min_depth = 0;
if node.is_none(){
return min_depth
}
let mut stack = vec![node.unwrap()];
while !stack.is_empty(){
min_depth += 1;
let num = stack.len();
for _i in 0..num{
let top = stack.remove(0);
let left_child = top.borrow_mut().left.take();
let right_child = top.borrow_mut().right.take();
if left_child.is_none() && right_child.is_none(){
return min_depth;
}
if left_child.is_some(){
stack.push(left_child.unwrap());
}
if right_child.is_some(){
stack.push(right_child.unwrap());
}
}
}
min_depth
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -377,22 +377,22 @@ class solution {
```java
class solution {
public list<list<integer>> pathsum(treenode root, int targetsum) {
list<list<integer>> res = new arraylist<>();
public List<List<Integer>> pathsum(TreeNode root, int targetsum) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res; // 非空判断
list<integer> path = new linkedlist<>();
List<Integer> path = new LinkedList<>();
preorderdfs(root, targetsum, res, path);
return res;
}
public void preorderdfs(treenode root, int targetsum, list<list<integer>> res, list<integer> path) {
public void preorderdfs(TreeNode root, int targetsum, List<List<Integer>> res, List<Integer> path) {
path.add(root.val);
// 遇到了叶子节点
if (root.left == null && root.right == null) {
// 找到了和为 targetsum 的路径
if (targetsum - root.val == 0) {
res.add(new arraylist<>(path));
res.add(new ArrayList<>(path));
}
return; // 如果和不为 targetsum返回
}

View File

@ -267,6 +267,36 @@ const numDistinct = (s, t) => {
};
```
TypeScript
```typescript
function numDistinct(s: string, t: string): number {
/**
dp[i][j]: s前i个字符t前j个字符s子序列中t出现的个数
dp[0][0]=1, 表示s前0个字符为''t前0个字符为''
*/
const sLen: number = s.length,
tLen: number = t.length;
const dp: number[][] = new Array(sLen + 1).fill(0)
.map(_ => new Array(tLen + 1).fill(0));
for (let m = 0; m < sLen; m++) {
dp[m][0] = 1;
}
for (let i = 1; i <= sLen; i++) {
for (let j = 1; j <= tLen; j++) {
if (s[i - 1] === t[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[sLen][tLen];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -426,6 +426,46 @@ var maxProfit = function(prices) {
};
```
TypeScript
> 贪心法
```typescript
function maxProfit(prices: number[]): number {
if (prices.length === 0) return 0;
let buy: number = prices[0];
let profitMax: number = 0;
for (let i = 1, length = prices.length; i < length; i++) {
profitMax = Math.max(profitMax, prices[i] - buy);
buy = Math.min(prices[i], buy);
}
return profitMax;
};
```
> 动态规划
```typescript
function maxProfit(prices: number[]): number {
/**
dp[i][0]: 第i天持有股票的最大现金
dp[i][1]: 第i天不持有股票的最大现金
*/
const length = prices.length;
if (length === 0) return 0;
const dp: number[][] = [];
dp[0] = [-prices[0], 0];
for (let i = 1; i < length; i++) {
dp[i] = [];
dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);
dp[i][1] = Math.max(dp[i - 1][0] + prices[i], dp[i - 1][1]);
}
return dp[length - 1][1];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -295,6 +295,42 @@ const maxProfit = (prices) => {
}
```
TypeScript
> 动态规划
```typescript
function maxProfit(prices: number[]): number {
/**
dp[i][0]: 第i天持有股票
dp[i][1]: 第i天不持有股票
*/
const length: number = prices.length;
if (length === 0) return 0;
const dp: number[][] = new Array(length).fill(0).map(_ => []);
dp[0] = [-prices[0], 0];
for (let i = 1; i < 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[length - 1][1];
};
```
> 贪心法
```typescript
function maxProfit(prices: number[]): number {
let resProfit: number = 0;
for (let i = 1, length = prices.length; i < length; i++) {
if (prices[i] > prices[i - 1]) {
resProfit += prices[i] - prices[i - 1];
}
}
return resProfit;
};
```
-----------------------

View File

@ -352,6 +352,36 @@ const maxProfit = prices => {
};
```
TypeScript
> 版本一
```typescript
function maxProfit(prices: number[]): number {
/**
dp[i][0]: 无操作;
dp[i][1]: 第一次买入;
dp[i][2]: 第一次卖出;
dp[i][3]: 第二次买入;
dp[i][4]: 第二次卖出;
*/
const length: number = prices.length;
if (length === 0) return 0;
const dp: number[][] = new Array(length).fill(0)
.map(_ => new Array(5).fill(0));
dp[0][1] = -prices[0];
dp[0][3] = -prices[0];
for (let i = 1; i < length; i++) {
dp[i][0] = dp[i - 1][0];
dp[i][1] = Math.max(dp[i - 1][1], -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 Math.max(dp[length - 1][2], dp[length - 1][4]);
};
```
Go:
> 版本一:

View File

@ -442,7 +442,7 @@ var partition = function(s) {
}
for(let j = i; j < len; j++) {
if(!isPalindrome(s, i, j)) continue;
path.push(s.substr(i, j - i + 1));
path.push(s.slice(i, j + 1));
backtracking(j + 1);
path.pop();
}

View File

@ -213,6 +213,25 @@ func findMax(num1 int ,num2 int) int{
}
```
### Rust
```rust
pub fn candy(ratings: Vec<i32>) -> i32 {
let mut candies = vec![1i32; ratings.len()];
for i in 1..ratings.len() {
if ratings[i - 1] < ratings[i] {
candies[i] = candies[i - 1] + 1;
}
}
for i in (0..ratings.len()-1).rev() {
if ratings[i] > ratings[i + 1] {
candies[i] = candies[i].max(candies[i + 1] + 1);
}
}
candies.iter().sum()
}
```
### Javascript:
```Javascript
var candy = function(ratings) {

View File

@ -345,6 +345,48 @@ const wordBreak = (s, wordDict) => {
}
```
TypeScript
> 动态规划
```typescript
function wordBreak(s: string, wordDict: string[]): boolean {
const dp: boolean[] = new Array(s.length + 1).fill(false);
dp[0] = true;
for (let i = 1; i <= s.length; i++) {
for (let j = 0; j < i; j++) {
const tempStr: string = s.slice(j, i);
if (wordDict.includes(tempStr) && dp[j] === true) {
dp[i] = true;
break;
}
}
}
return dp[s.length];
};
```
> 记忆化回溯
```typescript
function wordBreak(s: string, wordDict: string[]): boolean {
// 只需要记忆结果为false的情况
const memory: boolean[] = [];
return backTracking(s, wordDict, 0, memory);
function backTracking(s: string, wordDict: string[], startIndex: number, memory: boolean[]): boolean {
if (startIndex >= s.length) return true;
if (memory[startIndex] === false) return false;
for (let i = startIndex + 1, length = s.length; i <= length; i++) {
const str: string = s.slice(startIndex, i);
if (wordDict.includes(str) && backTracking(s, wordDict, i, memory))
return true;
}
memory[startIndex] = false;
return false;
}
};
```
-----------------------

View File

@ -370,7 +370,31 @@ ListNode *detectCycle(ListNode *head) {
}
```
Scala:
```scala
object Solution {
def detectCycle(head: ListNode): ListNode = {
var fast = head // 快指针
var slow = head // 慢指针
while (fast != null && fast.next != null) {
fast = fast.next.next // 快指针一次走两步
slow = slow.next // 慢指针一次走一步
// 如果相遇fast快指针回到头
if (fast == slow) {
fast = head
// 两个指针一步一步的走,第一次相遇的节点必是入环节点
while (fast != slow) {
fast = fast.next
slow = slow.next
}
return fast
}
}
// 如果fast指向空值必然无环返回null
null
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -136,19 +136,19 @@ java:
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList();
for (int i = 0; i < tokens.length; ++i) {
if ("+".equals(tokens[i])) { // leetcode 内置jdk的问题不能使用==判断字符串是否相等
for (String s : tokens) {
if ("+".equals(s)) { // leetcode 内置jdk的问题不能使用==判断字符串是否相等
stack.push(stack.pop() + stack.pop()); // 注意 - 和/ 需要特殊处理
} else if ("-".equals(tokens[i])) {
} else if ("-".equals(s)) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(tokens[i])) {
} else if ("*".equals(s)) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(tokens[i])) {
} else if ("/".equals(s)) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
stack.push(Integer.valueOf(tokens[i]));
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
@ -325,6 +325,33 @@ func evalRPN(_ tokens: [String]) -> Int {
return stack.last!
}
```
Scala:
```scala
object Solution {
import scala.collection.mutable
def evalRPN(tokens: Array[String]): Int = {
val stack = mutable.Stack[Int]() // 定义栈
// 抽取运算操作需要传递x,y和一个函数
def operator(x: Int, y: Int, f: (Int, Int) => Int): Int = f(x, y)
for (token <- tokens) {
// 模式匹配,匹配不同的操作符做什么样的运算
token match {
// 最后一个参数 _+_代表x+y遵循Scala的函数至简原则以下运算同理
case "+" => stack.push(operator(stack.pop(), stack.pop(), _ + _))
case "-" => stack.push(operator(stack.pop(), stack.pop(), -_ + _))
case "*" => stack.push(operator(stack.pop(), stack.pop(), _ * _))
case "/" => {
var pop1 = stack.pop()
var pop2 = stack.pop()
stack.push(operator(pop2, pop1, _ / _))
}
case _ => stack.push(token.toInt) // 不是运算符就入栈
}
}
// 最后返回栈顶不需要加return关键字
stack.pop()
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -758,7 +758,63 @@ func reverseWord(_ s: inout [Character]) {
}
```
Scala:
```scala
object Solution {
def reverseWords(s: String): String = {
var sb = removeSpace(s) // 移除多余的空格
reverseString(sb, 0, sb.length - 1) // 翻转字符串
reverseEachWord(sb)
sb.mkString
}
// 移除多余的空格
def removeSpace(s: String): Array[Char] = {
var start = 0
var end = s.length - 1
// 移除字符串前面的空格
while (start < s.length && s(start) == ' ') start += 1
// 移除字符串后面的空格
while (end >= 0 && s(end) == ' ') end -= 1
var sb = "" // String
// 当start小于等于end的时候执行添加操作
while (start <= end) {
var c = s(start)
// 当前字符不等于空sb的最后一个字符不等于空的时候添加到sb
if (c != ' ' || sb(sb.length - 1) != ' ') {
sb ++= c.toString
}
start += 1 // 指针向右移动
}
sb.toArray
}
// 翻转字符串
def reverseString(s: Array[Char], start: Int, end: Int): Unit = {
var (left, right) = (start, end)
while (left < right) {
var tmp = s(left)
s(left) = s(right)
s(right) = tmp
left += 1
right -= 1
}
}
// 翻转每个单词
def reverseEachWord(s: Array[Char]): Unit = {
var i = 0
while (i < s.length) {
var j = i + 1
// 向后迭代寻找每个单词的坐标
while (j < s.length && s(j) != ' ') j += 1
reverseString(s, i, j - 1) // 翻转每个单词
i = j + 1 // i往后更新
}
}
}
```

View File

@ -409,5 +409,27 @@ var maxProfit = function(k, prices) {
};
```
TypeScript
```typescript
function maxProfit(k: number, prices: number[]): number {
const length: number = prices.length;
if (length === 0) return 0;
const dp: number[][] = new Array(length).fill(0)
.map(_ => new Array(k * 2 + 1).fill(0));
for (let i = 1; i <= k; i++) {
dp[0][i * 2 - 1] = -prices[0];
}
for (let i = 1; i < length; i++) {
for (let j = 1; j < 2 * k + 1; j++) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + Math.pow(-1, j) * prices[i]);
}
}
return dp[length - 1][2 * k];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -189,6 +189,29 @@ const rob = nums => {
};
```
TypeScript
```typescript
function rob(nums: number[]): number {
/**
dp[i]: 前i个房屋能偷到的最大金额
dp[0]: nums[0];
dp[1]: max(nums[0], nums[1]);
...
dp[i]: max(dp[i-1], dp[i-2]+nums[i]);
*/
const length: number = nums.length;
if (length === 1) return nums[0];
const dp: number[] = [];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for (let i = 2; i < length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[length - 1];
};
```

View File

@ -385,5 +385,62 @@ bool isHappy(int n){
return bHappy;
}
```
Scala:
```scala
object Solution {
// 引入mutable
import scala.collection.mutable
def isHappy(n: Int): Boolean = {
// 存放每次计算后的结果
val set: mutable.HashSet[Int] = new mutable.HashSet[Int]()
var tmp = n // 因为形参是不可变量,所以需要找到一个临时变量
// 开始进入循环
while (true) {
val sum = getSum(tmp) // 获取这个数每个值的平方和
if (sum == 1) return true // 如果最终等于 1则返回true
// 如果set里面已经有这个值了说明进入无限循环可以返回false否则添加这个值到set
if (set.contains(sum)) return false
else set.add(sum)
tmp = sum
}
// 最终需要返回值直接返回个false
false
}
def getSum(n: Int): Int = {
var sum = 0
var tmp = n
while (tmp != 0) {
sum += (tmp % 10) * (tmp % 10)
tmp = tmp / 10
}
sum
}
```
C#
```csharp
public class Solution {
private int getSum(int n) {
int sum = 0;
//每位数的换算
while (n > 0) {
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
public bool IsHappy(int n) {
HashSet <int> set = new HashSet<int>();
while(n != 1 && !set.Contains(n)) { //判断避免循环
set.Add(n);
n = getSum(n);
}
return n == 1;
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -266,6 +266,27 @@ public ListNode removeElements(ListNode head, int val) {
}
return head;
}
/**
* 不添加虚拟节点and pre Node方式
* 时间复杂度 O(n)
* 空间复杂度 O(1)
* @param head
* @param val
* @return
*/
public ListNode removeElements(ListNode head, int val) {
while(head!=null && head.val==val){
head = head.next;
}
ListNode curr = head;
while(curr!=null){
while(curr.next!=null && curr.next.val == val){
curr.next = curr.next.next;
}
curr = curr.next;
}
return head;
}
```
Python
@ -478,6 +499,36 @@ impl Solution {
}
}
```
Scala:
```scala
/**
* Definition for singly-linked list.
* class ListNode(_x: Int = 0, _next: ListNode = null) {
* var next: ListNode = _next
* var x: Int = _x
* }
*/
object Solution {
def removeElements(head: ListNode, `val`: Int): ListNode = {
if (head == null) return head
var dummy = new ListNode(-1, head) // 定义虚拟头节点
var cur = head // cur 表示当前节点
var pre = dummy // pre 表示cur前一个节点
while (cur != null) {
if (cur.x == `val`) {
// 相等就删除那么cur的前一个节点pre执行cur的下一个
pre.next = cur.next
} else {
// 不相等pre就等于当前cur节点
pre = cur
}
// 向下迭代
cur = cur.next
}
// 最终返回dummy的下一个就是链表的头
dummy.next
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -496,6 +496,40 @@ struct ListNode* reverseList(struct ListNode* head){
return reverse(NULL, head);
}
```
Scala:
双指针法:
```scala
object Solution {
def reverseList(head: ListNode): ListNode = {
var pre: ListNode = null
var cur = head
while (cur != null) {
var tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
}
pre
}
}
```
递归法:
```scala
object Solution {
def reverseList(head: ListNode): ListNode = {
reverse(null, head)
}
def reverse(pre: ListNode, cur: ListNode): ListNode = {
if (cur == null) {
return pre // 如果当前cur为空则返回pre
}
val tmp: ListNode = cur.next
cur.next = pre
reverse(cur, tmp) // 此时cur成为前一个节点tmp是当前节点
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -5,7 +5,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
## 209.长度最小的子数组
# 209.长度最小的子数组
[力扣题目链接](https://leetcode-cn.com/problems/minimum-size-subarray-sum/)
@ -17,6 +17,9 @@
输出2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
# 思路
为了易于大家理解,我特意录制了[拿下滑动窗口! | LeetCode 209 长度最小的子数组](https://www.bilibili.com/video/BV1tZ4y1q7XE)
## 暴力解法
@ -47,8 +50,8 @@ public:
}
};
```
时间复杂度O(n^2)
空间复杂度O(1)
* 时间复杂度O(n^2)
* 空间复杂度O(1)
## 滑动窗口
@ -56,6 +59,20 @@ public:
所谓滑动窗口,**就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果**。
在暴力解法中是一个for循环滑动窗口的起始位置一个for循环为滑动窗口的终止位置用两个for循环 完成了一个不断搜索区间的过程。
那么滑动窗口如何用一个for循环来完成这个操作呢。
首先要思考 如果用一个for循环那么应该表示 滑动窗口的起始位置,还是终止位置。
如果只用一个for循环来表示 滑动窗口的起始位置,那么如何遍历剩下的终止位置?
此时难免再次陷入 暴力解法的怪圈。
所以 只用一个for循环那么这个循环的索引一定是表示 滑动窗口的终止位置。
那么问题来了, 滑动窗口的起始位置如何移动呢?
这里还是以题目中的示例来举例s=7 数组是 231243来看一下查找的过程
![209.长度最小的子数组](https://code-thinking.cdn.bcebos.com/gifs/209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.gif)
@ -74,7 +91,7 @@ public:
窗口的起始位置如何移动如果当前窗口的值大于s了窗口就要向前移动了也就是该缩小了
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,窗口的起始位置设置为数组的起始位置就可以了
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引
解题的关键在于 窗口的起始位置如何移动,如图所示:
@ -107,8 +124,8 @@ public:
};
```
时间复杂度O(n)
空间复杂度O(1)
* 时间复杂度O(n)
* 空间复杂度O(1)
**一些录友会疑惑为什么时间复杂度是O(n)**。
@ -400,6 +417,54 @@ class Solution {
}
}
```
Scala:
滑动窗口:
```scala
object Solution {
def minSubArrayLen(target: Int, nums: Array[Int]): Int = {
var result = Int.MaxValue // 返回结果,默认最大值
var left = 0 // 慢指针当sum>=target向右移动
var sum = 0 // 窗口值的总和
for (right <- 0 until nums.length) {
sum += nums(right)
while (sum >= target) {
result = math.min(result, right - left + 1) // 产生新结果
sum -= nums(left) // 左指针移动,窗口总和减去左指针的值
left += 1 // 左指针向右移动
}
}
// 相当于三元运算符return关键字可以省略
if (result == Int.MaxValue) 0 else result
}
}
```
暴力解法:
```scala
object Solution {
def minSubArrayLen(target: Int, nums: Array[Int]): Int = {
import scala.util.control.Breaks
var res = Int.MaxValue
var subLength = 0
for (i <- 0 until nums.length) {
var sum = 0
Breaks.breakable(
for (j <- i until nums.length) {
sum += nums(j)
if (sum >= target) {
subLength = j - i + 1
res = math.min(subLength, res)
Breaks.break()
}
}
)
}
// 相当于三元运算符
if (res == Int.MaxValue) 0 else res
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -165,7 +165,30 @@ const robRange = (nums, start, end) => {
return dp[end]
}
```
TypeScript
```typescript
function rob(nums: number[]): number {
const length: number = nums.length;
if (length === 0) return 0;
if (length === 1) return nums[0];
return Math.max(robRange(nums, 0, length - 2),
robRange(nums, 1, length - 1));
};
function robRange(nums: number[], start: number, end: number): number {
if (start === end) return nums[start];
const dp: number[] = [];
dp[start] = nums[start];
dp[start + 1] = Math.max(nums[start], nums[start + 1]);
for (let i = start + 2; i <= end; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[end];
}
```
Go
```go
// 打家劫舍Ⅱ 动态规划
// 时间复杂度O(n) 空间复杂度O(n)

View File

@ -360,39 +360,30 @@ func backTree(n,k,startIndex int,track *[]int,result *[][]int){
## javaScript
```js
// 等差数列
var maxV = k => k * (9 + 10 - k) / 2;
var minV = k => k * (1 + k) / 2;
/**
* @param {number} k
* @param {number} n
* @return {number[][]}
*/
var combinationSum3 = function(k, n) {
if (k > 9 || k < 1) return [];
// if (n > maxV(k) || n < minV(k)) return [];
// if (n === maxV(k)) return [Array.from({length: k}).map((v, i) => 9 - i)];
// if (n === minV(k)) return [Array.from({length: k}).map((v, i) => i + 1)];
const res = [], path = [];
backtracking(k, n, 1, 0);
return res;
function backtracking(k, n, i, sum){
const len = path.length;
if (len > k || sum > n) return;
if (maxV(k - len) < n - sum) return;
if (minV(k - len) > n - sum) return;
if(len === k && sum == n) {
res.push(Array.from(path));
const backtrack = (start) => {
const l = path.length;
if (l === k) {
const sum = path.reduce((a, b) => a + b);
if (sum === n) {
res.push([...path]);
}
return;
}
const min = Math.min(n - sum, 9 + len - k + 1);
for(let a = i; a <= min; a++) {
path.push(a);
sum += a;
backtracking(k, n, a + 1, sum);
for (let i = start; i <= 9 - (k - l) + 1; i++) {
path.push(i);
backtrack(i + 1);
path.pop();
sum -= a;
}
}
let res = [], path = [];
backtrack(1);
return res;
};
```

View File

@ -646,5 +646,68 @@ func countNodes(_ root: TreeNode?) -> Int {
}
```
## Scala
递归:
```scala
object Solution {
def countNodes(root: TreeNode): Int = {
if(root == null) return 0
1 + countNodes(root.left) + countNodes(root.right)
}
}
```
层序遍历:
```scala
object Solution {
import scala.collection.mutable
def countNodes(root: TreeNode): Int = {
if (root == null) return 0
val queue = mutable.Queue[TreeNode]()
var node = 0
queue.enqueue(root)
while (!queue.isEmpty) {
val len = queue.size
for (i <- 0 until len) {
node += 1
val curNode = queue.dequeue()
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
}
}
node
}
}
```
利用完全二叉树性质:
```scala
object Solution {
def countNodes(root: TreeNode): Int = {
if (root == null) return 0
var leftNode = root.left
var rightNode = root.right
// 向左向右往下探
var leftDepth = 0
while (leftNode != null) {
leftDepth += 1
leftNode = leftNode.left
}
var rightDepth = 0
while (rightNode != null) {
rightDepth += 1
rightNode = rightNode.right
}
// 如果相等就是一个满二叉树
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1
}
// 如果不相等就不是一个完全二叉树,继续向下递归
countNodes(root.left) + countNodes(root.right) + 1
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -815,6 +815,89 @@ class MyStack {
}
}
```
Scala:
使用两个队列模拟栈:
```scala
import scala.collection.mutable
class MyStack() {
val queue1 = new mutable.Queue[Int]()
val queue2 = new mutable.Queue[Int]()
def push(x: Int) {
queue1.enqueue(x)
}
def pop(): Int = {
var size = queue1.size
// 将queue1中的每个元素都移动到queue2
for (i <- 0 until size - 1) {
queue2.enqueue(queue1.dequeue())
}
var res = queue1.dequeue()
// 再将queue2中的每个元素都移动到queue1
while (!queue2.isEmpty) {
queue1.enqueue(queue2.dequeue())
}
res
}
def top(): Int = {
var size = queue1.size
for (i <- 0 until size - 1) {
queue2.enqueue(queue1.dequeue())
}
var res = queue1.dequeue()
while (!queue2.isEmpty) {
queue1.enqueue(queue2.dequeue())
}
// 最终还需要把res送进queue1
queue1.enqueue(res)
res
}
def empty(): Boolean = {
queue1.isEmpty
}
}
```
使用一个队列模拟:
```scala
import scala.collection.mutable
class MyStack() {
val queue = new mutable.Queue[Int]()
def push(x: Int) {
queue.enqueue(x)
}
def pop(): Int = {
var size = queue.size
for (i <- 0 until size - 1) {
queue.enqueue(queue.head) // 把头添到队列最后
queue.dequeue() // 再出队
}
queue.dequeue()
}
def top(): Int = {
var size = queue.size
var res = 0
for (i <- 0 until size) {
queue.enqueue(queue.head) // 把头添到队列最后
res = queue.dequeue() // 再出队
}
res
}
def empty(): Boolean = {
queue.isEmpty
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -368,9 +368,7 @@ func invertTree(root *TreeNode) *TreeNode {
if root ==nil{
return nil
}
temp:=root.Left
root.Left=root.Right
root.Right=temp
root.Left,root.Right=root.Right,root.Left//交换
invertTree(root.Left)
invertTree(root.Right)
@ -820,5 +818,53 @@ func invertTree(_ root: TreeNode?) -> TreeNode? {
}
```
### Scala
深度优先遍历(前序遍历):
```scala
object Solution {
def invertTree(root: TreeNode): TreeNode = {
if (root == null) return root
// 递归
def process(node: TreeNode): Unit = {
if (node == null) return
// 翻转节点
val curNode = node.left
node.left = node.right
node.right = curNode
process(node.left)
process(node.right)
}
process(root)
root
}
}
```
广度优先遍历(层序遍历):
```scala
object Solution {
import scala.collection.mutable
def invertTree(root: TreeNode): TreeNode = {
if (root == null) return root
val queue = mutable.Queue[TreeNode]()
queue.enqueue(root)
while (!queue.isEmpty) {
val len = queue.size
for (i <- 0 until len) {
var curNode = queue.dequeue()
if (curNode.left != null) queue.enqueue(curNode.left)
if (curNode.right != null) queue.enqueue(curNode.right)
// 翻转
var tmpNode = curNode.left
curNode.left = curNode.right
curNode.right = tmpNode
}
}
root
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -495,6 +495,45 @@ void myQueueFree(MyQueue* obj) {
obj->stackOutTop = 0;
}
```
Scala:
```scala
class MyQueue() {
import scala.collection.mutable
val stackIn = mutable.Stack[Int]() // 负责出栈
val stackOut = mutable.Stack[Int]() // 负责入栈
// 添加元素
def push(x: Int) {
stackIn.push(x)
}
// 复用代码如果stackOut为空就把stackIn的所有元素都压入StackOut
def dumpStackIn(): Unit = {
if (!stackOut.isEmpty) return
while (!stackIn.isEmpty) {
stackOut.push(stackIn.pop())
}
}
// 弹出元素
def pop(): Int = {
dumpStackIn()
stackOut.pop()
}
// 获取队头
def peek(): Int = {
dumpStackIn()
val res: Int = stackOut.pop()
stackOut.push(res)
res
}
// 判断是否为空
def empty(): Boolean = {
stackIn.isEmpty && stackOut.isEmpty
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -630,6 +630,53 @@ func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] {
return result
}
```
Scala:
```scala
import scala.collection.mutable.ArrayBuffer
object Solution {
def maxSlidingWindow(nums: Array[Int], k: Int): Array[Int] = {
var len = nums.length - k + 1 // 滑动窗口长度
var res: Array[Int] = new Array[Int](len) // 声明存储结果的数组
var index = 0 // 结果数组指针
val queue: MyQueue = new MyQueue // 自定义队列
// 将前k个添加到queue
for (i <- 0 until k) {
queue.add(nums(i))
}
res(index) = queue.peek // 第一个滑动窗口的最大值
index += 1
for (i <- k until nums.length) {
queue.poll(nums(i - k)) // 首先移除第i-k个元素
queue.add(nums(i)) // 添加当前数字到队列
res(index) = queue.peek() // 赋值
index+=1
}
// 最终返回resreturn关键字可以省略
res
}
}
class MyQueue {
var queue = ArrayBuffer[Int]()
// 移除元素,如果传递进来的跟队头相等,那么移除
def poll(value: Int): Unit = {
if (!queue.isEmpty && queue.head == value) {
queue.remove(0)
}
}
// 添加元素,当队尾大于当前元素就删除
def add(value: Int): Unit = {
while (!queue.isEmpty && value > queue.last) {
queue.remove(queue.length - 1)
}
queue.append(value)
}
def peek(): Int = queue.head
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -307,6 +307,52 @@ impl Solution {
}
}
```
Scala:
```scala
object Solution {
def isAnagram(s: String, t: String): Boolean = {
// 如果两个字符串的长度不等直接返回false
if (s.length != t.length) return false
val record = new Array[Int](26) // 记录每个单词出现了多少次
// 遍历字符串对于s字符串单词对应的记录+=1t字符串对应的记录-=1
for (i <- 0 until s.length) {
record(s(i) - 97) += 1
record(t(i) - 97) -= 1
}
// 如果不等于则直接返回false
for (i <- 0 until 26) {
if (record(i) != 0) {
return false
}
}
// 如果前面不返回false说明匹配成功返回truereturn可以省略
true
}
}
```
C#
```csharp
public bool IsAnagram(string s, string t) {
int sl=s.Length,tl=t.Length;
if(sl!=tl) return false;
int[] a = new int[26];
for(int i = 0; i < sl; i++){
a[s[i] - 'a']++;
a[t[i] - 'a']--;
}
foreach (int i in a)
{
if (i != 0)
return false;
}
return true;
}
```
## 相关题目
* 383.赎金信

View File

@ -702,5 +702,35 @@ func binaryTreePaths(_ root: TreeNode?) -> [String] {
}
```
Scala:
递归:
```scala
object Solution {
import scala.collection.mutable.ListBuffer
def binaryTreePaths(root: TreeNode): List[String] = {
val res = ListBuffer[String]()
def traversal(curNode: TreeNode, path: ListBuffer[Int]): Unit = {
path.append(curNode.value)
if (curNode.left == null && curNode.right == null) {
res.append(path.mkString("->")) // mkString函数: 将数组的所有值按照指定字符串拼接
return // 处理完可以直接return
}
if (curNode.left != null) {
traversal(curNode.left, path)
path.remove(path.size - 1)
}
if (curNode.right != null) {
traversal(curNode.right, path)
path.remove(path.size - 1)
}
}
traversal(root, ListBuffer[Int]())
res.toList
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -355,5 +355,24 @@ var numSquares2 = function(n) {
};
```
TypeScript
```typescript
function numSquares(n: number): number {
const goodsNum: number = Math.floor(Math.sqrt(n));
const dp: number[] = new Array(n + 1).fill(Infinity);
dp[0] = 0;
for (let i = 1; i <= goodsNum; i++) {
const tempVal: number = i * i;
for (let j = tempVal; j <= n; j++) {
dp[j] = Math.min(dp[j], dp[j - tempVal] + 1);
}
}
return dp[n];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -201,6 +201,23 @@ func max(x, y int) int {
}
```
Rust:
```rust
pub fn length_of_lis(nums: Vec<i32>) -> i32 {
let mut dp = vec![1; nums.len() + 1];
let mut result = 1;
for i in 1..nums.len() {
for j in 0..i {
if nums[j] < nums[i] {
dp[i] = dp[i].max(dp[j] + 1);
}
result = result.max(dp[i]);
}
}
result
}
```
Javascript
```javascript
const lengthOfLIS = (nums) => {
@ -220,6 +237,27 @@ const lengthOfLIS = (nums) => {
};
```
TypeScript
```typescript
function lengthOfLIS(nums: number[]): number {
/**
dp[i]: 前i个元素中以nums[i]结尾,最长子序列的长度
*/
const dp: number[] = new Array(nums.length).fill(1);
let resMax: number = 0;
for (let i = 0, length = nums.length; i < length; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
resMax = Math.max(resMax, dp[i]);
}
return resMax;
};
```

View File

@ -325,6 +325,66 @@ const maxProfit = (prices) => {
};
```
TypeScript
> 版本一,与本文思路一致
```typescript
function maxProfit(prices: number[]): number {
/**
dp[i][0]: 持股状态;
dp[i][1]: 无股状态,当天为非冷冻期;
dp[i][2]: 无股状态,当天卖出;
dp[i][3]: 无股状态,当天为冷冻期;
*/
const length: number = prices.length;
const dp: number[][] = new Array(length).fill(0).map(_ => []);
dp[0][0] = -prices[0];
dp[0][1] = dp[0][2] = dp[0][3] = 0;
for (let i = 1; i < length; i++) {
dp[i][0] = Math.max(
dp[i - 1][0],
Math.max(dp[i - 1][1], dp[i - 1][3]) - 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];
}
const lastEl: number[] = dp[length - 1];
return Math.max(lastEl[1], lastEl[2], lastEl[3]);
};
```
> 版本二,状态定义略有不同,可以帮助理解
```typescript
function maxProfit(prices: number[]): number {
/**
dp[i][0]: 持股状态,当天买入;
dp[i][1]: 持股状态,当天未买入;
dp[i][2]: 无股状态,当天卖出;
dp[i][3]: 无股状态,当天未卖出;
买入有冷冻期限制,其实就是状态[0]只能由前一天的状态[3]得到;
如果卖出有冷冻期限制,其实就是[2]由[1]得到。
*/
const length: number = prices.length;
const dp: number[][] = new Array(length).fill(0).map(_ => []);
dp[0][0] = -prices[0];
dp[0][1] = -Infinity;
dp[0][2] = dp[0][3] = 0;
for (let i = 1; i < length; i++) {
dp[i][0] = dp[i - 1][3] - prices[i];
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0]);
dp[i][2] = Math.max(dp[i - 1][0], dp[i - 1][1]) + prices[i];
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2]);
}
return Math.max(dp[length - 1][2], dp[length - 1][3]);
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -302,6 +302,24 @@ func min(a, b int) int {
```
Rust:
```rust
pub fn coin_change(coins: Vec<i32>, amount: i32) -> i32 {
let amount = amount as usize;
let mut dp = vec![i32::MAX; amount + 1];
dp[0] = 0;
for i in 0..coins.len() {
for j in coins[i] as usize..=amount {
if dp[j - coins[i] as usize] != i32::MAX {
dp[j] = dp[j].min(dp[j - coins[i] as usize] + 1);
}
}
}
if dp[amount] == i32::MAX { -1 } else { dp[amount] }
}
```
Javascript
```javascript
const coinChange = (coins, amount) => {
@ -322,7 +340,21 @@ const coinChange = (coins, amount) => {
}
```
TypeScript
```typescript
function coinChange(coins: number[], amount: number): number {
const dp: number[] = new Array(amount + 1).fill(Infinity);
dp[0] = 0;
for (let i = 0; i < coins.length; i++) {
for (let j = coins[i]; j <= amount; j++) {
if (dp[j - coins[i]] === Infinity) continue;
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
return dp[amount] === Infinity ? -1 : dp[amount];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -429,7 +429,50 @@ const rob = root => {
};
```
### TypeScript
> 记忆化后序遍历
```typescript
const memory: Map<TreeNode, number> = new Map();
function rob(root: TreeNode | null): number {
if (root === null) return 0;
if (memory.has(root)) return memory.get(root);
// 不取当前节点
const res1: number = rob(root.left) + rob(root.right);
// 取当前节点
let res2: number = root.val;
if (root.left !== null) res2 += rob(root.left.left) + rob(root.left.right);
if (root.right !== null) res2 += rob(root.right.left) + rob(root.right.right);
const res: number = Math.max(res1, res2);
memory.set(root, res);
return res;
};
```
> 状态标记化后序遍历
```typescript
function rob(root: TreeNode | null): number {
return Math.max(...robNode(root));
};
// [0]-不偷当前节点能获得的最大金额; [1]-偷~~
type MaxValueArr = [number, number];
function robNode(node: TreeNode | null): MaxValueArr {
if (node === null) return [0, 0];
const leftArr: MaxValueArr = robNode(node.left);
const rightArr: MaxValueArr = robNode(node.right);
// 不偷
const val1: number = Math.max(leftArr[0], leftArr[1]) +
Math.max(rightArr[0], rightArr[1]);
// 偷
const val2: number = leftArr[0] + rightArr[0] + node.val;
return [val1, val2];
}
```
### Go
```go
// 打家劫舍Ⅲ 动态规划
// 时间复杂度O(n) 空间复杂度O(logn)

View File

@ -274,7 +274,33 @@ var integerBreak = function(n) {
};
```
C:
### TypeScript
```typescript
function integerBreak(n: number): number {
/**
dp[i]: i对应的最大乘积
dp[2]: 1;
...
dp[i]: max(
1 * dp[i - 1], 1 * (i - 1),
2 * dp[i - 2], 2 * (i - 2),
..., (i - 2) * dp[2], (i - 2) * 2
);
*/
const dp: number[] = new Array(n + 1).fill(0);
dp[2] = 1;
for (let i = 3; i <= n; i++) {
for (let j = 1; j <= i - 2; j++) {
dp[i] = Math.max(dp[i], j * dp[i - j], j * (i - j));
}
}
return dp[n];
};
```
### C
```c
//初始化DP数组
int *initDP(int num) {

View File

@ -266,6 +266,20 @@ public class Solution
}
}
```
Scala:
```scala
object Solution {
def reverseString(s: Array[Char]): Unit = {
var (left, right) = (0, s.length - 1)
while (left < right) {
var tmp = s(left)
s(left) = s(right)
s(right) = tmp
left += 1
right -= 1
}
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -374,7 +374,49 @@ function topKFrequent(nums: number[], k: number): number[] {
};
```
Scala:
解法一: 优先级队列
```scala
object Solution {
import scala.collection.mutable
def topKFrequent(nums: Array[Int], k: Int): Array[Int] = {
val map = mutable.HashMap[Int, Int]()
// 将所有元素都放入Map
for (num <- nums) {
map.put(num, map.getOrElse(num, 0) + 1)
}
// 声明一个优先级队列,在函数柯里化那块需要指明排序方式
var queue = mutable.PriorityQueue[(Int, Int)]()(Ordering.fromLessThan((x, y) => x._2 > y._2))
// 将map里面的元素送入优先级队列
for (elem <- map) {
queue.enqueue(elem)
if(queue.size > k){
queue.dequeue // 如果队列元素大于k个出队
}
}
// 最终只需要key的Array形式就可以了return关键字可以省略
queue.map(_._1).toArray
}
}
```
解法二: 相当于一个wordCount程序
```scala
object Solution {
def topKFrequent(nums: Array[Int], k: Int): Array[Int] = {
// 首先将数据变为(x,1)然后按照x分组再使用map进行转换(x,sum)变换为Array
// 再使用sort针对sum进行排序最后take前k个再把数据变为x,y,z这种格式
nums.map((_, 1)).groupBy(_._1)
.map {
case (x, arr) => (x, arr.map(_._2).sum)
}
.toArray
.sortWith(_._2 > _._2)
.take(k)
.map(_._1)
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -313,6 +313,71 @@ int* intersection1(int* nums1, int nums1Size, int* nums2, int nums2Size, int* re
}
```
Scala:
正常解法:
```scala
object Solution {
def intersection(nums1: Array[Int], nums2: Array[Int]): Array[Int] = {
// 导入mutable
import scala.collection.mutable
// 临时Set用于记录数组1出现的每个元素
val tmpSet: mutable.HashSet[Int] = new mutable.HashSet[Int]()
// 结果Set存储最终结果
val resSet: mutable.HashSet[Int] = new mutable.HashSet[Int]()
// 遍历nums1把每个元素添加到tmpSet
nums1.foreach(tmpSet.add(_))
// 遍历nums2如果在tmpSet存在就添加到resSet
nums2.foreach(elem => {
if (tmpSet.contains(elem)) {
resSet.add(elem)
}
})
// 将结果转换为Array返回return可以省略
resSet.toArray
}
}
```
骚操作1:
```scala
object Solution {
def intersection(nums1: Array[Int], nums2: Array[Int]): Array[Int] = {
// 先转为Set然后取交集最后转换为Array
(nums1.toSet).intersect(nums2.toSet).toArray
}
}
```
骚操作2:
```scala
object Solution {
def intersection(nums1: Array[Int], nums2: Array[Int]): Array[Int] = {
// distinct去重然后取交集
(nums1.distinct).intersect(nums2.distinct)
}
}
```
C#:
```csharp
public int[] Intersection(int[] nums1, int[] nums2) {
if(nums1==null||nums1.Length==0||nums2==null||nums1.Length==0)
return new int[0]; //注意数组条件
HashSet<int> one = Insert(nums1);
HashSet<int> two = Insert(nums2);
one.IntersectWith(two);
return one.ToArray();
}
public HashSet<int> Insert(int[] nums){
HashSet<int> one = new HashSet<int>();
foreach(int num in nums){
one.Add(num);
}
return one;
}
```
## 相关题目
* 350.两个数组的交集 II

View File

@ -221,7 +221,27 @@ const combinationSum4 = (nums, target) => {
};
```
TypeScript
```typescript
function combinationSum4(nums: number[], target: number): number {
const dp: number[] = new Array(target + 1).fill(0);
dp[0] = 1;
// 遍历背包
for (let i = 1; i <= target; i++) {
// 遍历物品
for (let j = 0, length = nums.length; j < length; j++) {
if (i >= nums[j]) {
dp[i] += dp[i - nums[j]];
}
}
}
return dp[target];
};
```
Rust
```Rust
impl Solution {
pub fn combination_sum4(nums: Vec<i32>, target: i32) -> i32 {

View File

@ -114,23 +114,25 @@ 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]++;
// 定义一个哈希映射数组
int[] record = new int[26];
// 遍历
for(char c : magazine.toCharArray()){
record[c - 'a'] += 1;
}
for (int i = 0; i < ransomNote.length(); i++) {
temp = ransomNote.charAt(i) - 'a';
//对于金信中的每一个字符都在数组中查找
//找到相应位减一否则找不到返回false
if (arr[temp] > 0) {
arr[temp]--;
} else {
for(char c : ransomNote.toCharArray()){
record[c - 'a'] -= 1;
}
// 如果数组中存在负数说明ransomNote字符串总存在magazine中没有的字符
for(int i : record){
if(i < 0){
return false;
}
}
return true;
}
}
@ -361,5 +363,88 @@ impl Solution {
}
```
Scala:
版本一: 使用数组作为哈希表
```scala
object Solution {
def canConstruct(ransomNote: String, magazine: String): Boolean = {
// 如果magazine的长度小于ransomNote的长度必然是false
if (magazine.length < ransomNote.length) {
return false
}
// 定义一个数组存储magazine字符出现的次数
val map: Array[Int] = new Array[Int](26)
// 遍历magazine字符串对应的字符+=1
for (i <- magazine.indices) {
map(magazine(i) - 'a') += 1
}
// 遍历ransomNote
for (i <- ransomNote.indices) {
if (map(ransomNote(i) - 'a') > 0)
map(ransomNote(i) - 'a') -= 1
else return false
}
// 如果上面没有返回false直接返回true关键字return可以省略
true
}
}
```
```scala
object Solution {
import scala.collection.mutable
def canConstruct(ransomNote: String, magazine: String): Boolean = {
// 如果magazine的长度小于ransomNote的长度必然是false
if (magazine.length < ransomNote.length) {
return false
}
// 定义mapkey是字符value是字符出现的次数
val map = new mutable.HashMap[Char, Int]()
// 遍历magazine把所有的字符都记录到map里面
for (i <- magazine.indices) {
val tmpChar = magazine(i)
// 如果map包含该字符那么对应的value++,否则添加该字符
if (map.contains(tmpChar)) {
map.put(tmpChar, map.get(tmpChar).get + 1)
} else {
map.put(tmpChar, 1)
}
}
// 遍历ransomNote
for (i <- ransomNote.indices) {
val tmpChar = ransomNote(i)
// 如果map包含并且该字符的value大于0则匹配成功map对应的--否则直接返回false
if (map.contains(tmpChar) && map.get(tmpChar).get > 0) {
map.put(tmpChar, map.get(tmpChar).get - 1)
} else {
return false
}
}
// 如果上面没有返回false直接返回true关键字return可以省略
true
}
}
```
C#
```csharp
public bool CanConstruct(string ransomNote, string magazine) {
if(ransomNote.Length > magazine.Length) return false;
int[] letters = new int[26];
foreach(char c in magazine){
letters[c-'a']++;
}
foreach(char c in ransomNote){
letters[c-'a']--;
if(letters[c-'a']<0){
return false;
}
}
return true;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -201,7 +201,32 @@ const isSubsequence = (s, t) => {
};
```
TypeScript
```typescript
function isSubsequence(s: string, t: string): boolean {
/**
dp[i][j]: s的前i-1个t的前j-1个最长公共子序列的长度
*/
const sLen: number = s.length,
tLen: number = t.length;
const dp: number[][] = new Array(sLen + 1).fill(0)
.map(_ => new Array(tLen + 1).fill(0));
for (let i = 1; i <= sLen; i++) {
for (let j = 1; j <= tLen; j++) {
if (s[i - 1] === t[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 dp[sLen][tLen] === s.length;
};
```
Go
```go
func isSubsequence(s string, t string) bool {
dp := make([][]int,len(s)+1)

View File

@ -336,8 +336,8 @@ var sumOfLeftLeaves = function(root) {
if(node===null){
return 0;
}
let leftValue = sumOfLeftLeaves(node.left);
let rightValue = sumOfLeftLeaves(node.right);
let leftValue = nodesSum(node.left);
let rightValue = nodesSum(node.right);
// 3. 单层递归逻辑
let midValue = 0;
if(node.left&&node.left.left===null&&node.left.right===null){

View File

@ -416,6 +416,27 @@ var canPartition = function(nums) {
};
```
TypeScript:
```ts
function canPartition(nums: number[]): boolean {
const sum: number = nums.reduce((a: number, b: number): number => a + b);
if (sum % 2 === 1) return false;
const target: number = sum / 2;
// dp[j]表示容量总数和为j的背包所能装下的数下标[0, i]之间任意取)的总和(<= 容量)的最大值
const dp: number[] = new Array(target + 1).fill(0);
const n: number = nums.length;
for (let i: number = 0; i < n; i++) {
for (let j: number = target; j >= nums[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
return dp[target] === target;
};
```
C:
二维dp
```c
@ -517,6 +538,61 @@ bool canPartition(int* nums, int numsSize){
}
```
TypeScript:
> 一维数组,简洁
```typescript
function canPartition(nums: number[]): boolean {
const sum: number = nums.reduce((pre, cur) => pre + cur);
if (sum % 2 === 1) return false;
const bagSize: number = sum / 2;
const goodsNum: number = nums.length;
const dp: number[] = new Array(bagSize + 1).fill(0);
for (let i = 0; i < goodsNum; i++) {
for (let j = bagSize; j >= nums[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
return dp[bagSize] === bagSize;
};
```
> 二维数组,易懂
```typescript
function canPartition(nums: number[]): boolean {
/**
weightArr = nums;
valueArr = nums;
bagSize = sum / 2; (sum为nums各元素总和);
按照0-1背包处理
*/
const sum: number = nums.reduce((pre, cur) => pre + cur);
if (sum % 2 === 1) return false;
const bagSize: number = sum / 2;
const weightArr: number[] = nums;
const valueArr: number[] = nums;
const goodsNum: number = weightArr.length;
const dp: number[][] = new Array(goodsNum)
.fill(0)
.map(_ => new Array(bagSize + 1).fill(0));
for (let i = weightArr[0]; i <= bagSize; i++) {
dp[0][i] = valueArr[0];
}
for (let i = 1; i < goodsNum; i++) {
for (let j = 0; j <= bagSize; j++) {
if (j < weightArr[i]) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weightArr[i]] + valueArr[i]);
}
}
}
return dp[goodsNum - 1][bagSize] === bagSize;
};
```
-----------------------

View File

@ -93,7 +93,7 @@ public:
};
```
* 时间复杂度O(nlog n) ,有一个快排
* 空间复杂度O(1)
* 空间复杂度O(n),有一个快排,最差情况(倒序)时需要n次递归调用。因此确实需要O(n)的栈空间
大家此时会发现如此复杂的一个问题,代码实现却这么简单!

View File

@ -105,8 +105,8 @@ public:
};
```
* 时间复杂度:$O(n\log n)$,因为有一个快排
* 空间复杂度:$O(1)$
* 时间复杂度O(nlog n),因为有一个快排
* 空间复杂度:O(1),有一个快排,最差情况(倒序)时需要n次递归调用。因此确实需要O(n)的栈空间
可以看出代码并不复杂。

View File

@ -318,5 +318,70 @@ impl Solution {
}
```
Scala:
```scala
object Solution {
// 导包
import scala.collection.mutable
def fourSumCount(nums1: Array[Int], nums2: Array[Int], nums3: Array[Int], nums4: Array[Int]): Int = {
// 定义一个HashMapkey存储值value存储该值出现的次数
val map = new mutable.HashMap[Int, Int]()
// 遍历前两个数组把他们所有可能的情况都记录到map
for (i <- nums1.indices) {
for (j <- nums2.indices) {
val tmp = nums1(i) + nums2(j)
// 如果包含该值则对他的key加1不包含则添加进去
if (map.contains(tmp)) {
map.put(tmp, map.get(tmp).get + 1)
} else {
map.put(tmp, 1)
}
}
}
var res = 0 // 结果变量
// 遍历后两个数组
for (i <- nums3.indices) {
for (j <- nums4.indices) {
val tmp = -(nums3(i) + nums4(j))
// 如果map中存在该值结果就+=value
if (map.contains(tmp)) {
res += map.get(tmp).get
}
}
}
// 返回最终结果可以省略关键字return
res
}
}
```
C#
```csharp
public int FourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Dictionary<int, int> dic = new Dictionary<int, int>();
foreach(var i in nums1){
foreach(var j in nums2){
int sum = i + j;
if(dic.ContainsKey(sum)){
dic[sum]++;
}else{
dic.Add(sum, 1);
}
}
}
int res = 0;
foreach(var a in nums3){
foreach(var b in nums4){
int sum = a+b;
if(dic.TryGetValue(-sum, out var result)){
res += result;
}
}
}
return res;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -191,6 +191,26 @@ func findContentChildren(g []int, s []int) int {
}
```
### Rust
```rust
pub fn find_content_children(children: Vec<i32>, cookie: Vec<i32>) -> i32 {
let mut children = children;
let mut cookies = cookie;
children.sort();
cookies.sort();
let (mut child, mut cookie) = (0usize, 0usize);
while child < children.len() && cookie < cookies.len() {
// 优先选择最小饼干喂饱孩子
if children[child] <= cookies[cookie] {
child += 1;
}
cookie += 1
}
child as i32
}
```
### Javascript
```js
var findContentChildren = function(g, s) {

View File

@ -323,6 +323,129 @@ const findMaxForm = (strs, m, n) => {
};
```
TypeScript
> 滚动数组,二维数组法
```typescript
type BinaryInfo = { numOfZero: number, numOfOne: number };
function findMaxForm(strs: string[], m: number, n: number): number {
const goodsNum: number = strs.length;
const dp: number[][] = new Array(m + 1).fill(0)
.map(_ => new Array(n + 1).fill(0));
for (let i = 0; i < goodsNum; i++) {
const { numOfZero, numOfOne } = countBinary(strs[i]);
for (let j = m; j >= numOfZero; j--) {
for (let k = n; k >= numOfOne; k--) {
dp[j][k] = Math.max(dp[j][k], dp[j - numOfZero][k - numOfOne] + 1);
}
}
}
return dp[m][n];
};
function countBinary(str: string): BinaryInfo {
let numOfZero: number = 0,
numOfOne: number = 0;
for (let s of str) {
if (s === '0') {
numOfZero++;
} else {
numOfOne++;
}
}
return { numOfZero, numOfOne };
}
```
> 传统背包,三维数组法
```typescript
type BinaryInfo = { numOfZero: number, numOfOne: number };
function findMaxForm(strs: string[], m: number, n: number): number {
/**
dp[i][j][k]: 前i个物品中, 背包的0容量为j, 1容量为k, 最多能放的物品数量
*/
const goodsNum: number = strs.length;
const dp: number[][][] = new Array(goodsNum).fill(0)
.map(_ => new Array(m + 1)
.fill(0)
.map(_ => new Array(n + 1).fill(0))
);
const { numOfZero, numOfOne } = countBinary(strs[0]);
for (let i = numOfZero; i <= m; i++) {
for (let j = numOfOne; j <= n; j++) {
dp[0][i][j] = 1;
}
}
for (let i = 1; i < goodsNum; i++) {
const { numOfZero, numOfOne } = countBinary(strs[i]);
for (let j = 0; j <= m; j++) {
for (let k = 0; k <= n; k++) {
if (j < numOfZero || k < numOfOne) {
dp[i][j][k] = dp[i - 1][j][k];
} else {
dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - numOfZero][k - numOfOne] + 1);
}
}
}
}
return dp[dp.length - 1][m][n];
};
function countBinary(str: string): BinaryInfo {
let numOfZero: number = 0,
numOfOne: number = 0;
for (let s of str) {
if (s === '0') {
numOfZero++;
} else {
numOfOne++;
}
}
return { numOfZero, numOfOne };
}
```
> 回溯法(会超时)
```typescript
function findMaxForm(strs: string[], m: number, n: number): number {
/**
思路暴力枚举strs的所有子集记录符合条件子集的最大长度
*/
let resMax: number = 0;
backTrack(strs, m, n, 0, []);
return resMax;
function backTrack(
strs: string[], m: number, n: number,
startIndex: number, route: string[]
): void {
if (startIndex === strs.length) return;
for (let i = startIndex, length = strs.length; i < length; i++) {
route.push(strs[i]);
if (isValidSubSet(route, m, n)) {
resMax = Math.max(resMax, route.length);
backTrack(strs, m, n, i + 1, route);
}
route.pop();
}
}
};
function isValidSubSet(strs: string[], m: number, n: number): boolean {
let zeroNum: number = 0,
oneNum: number = 0;
strs.forEach(str => {
for (let s of str) {
if (s === '0') {
zeroNum++;
} else {
oneNum++;
}
}
});
return zeroNum <= m && oneNum <= n;
}
```
-----------------------

View File

@ -352,6 +352,29 @@ const findTargetSumWays = (nums, target) => {
```
TypeScript:
```ts
function findTargetSumWays(nums: number[], target: number): number {
// 把数组分成两个组合left, right.left + right = sum, left - right = target.
const sum: number = nums.reduce((a: number, b: number): number => a + b);
if ((sum + target) % 2 || Math.abs(target) > sum) return 0;
const left: number = (sum + target) / 2;
// 将问题转化为装满容量为left的背包有多少种方法
// dp[i]表示装满容量为i的背包有多少种方法
const dp: number[] = new Array(left + 1).fill(0);
dp[0] = 1; // 装满容量为0的背包有1种方法什么也不装
for (let i: number = 0; i < nums.length; i++) {
for (let j: number = left; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[left];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -244,6 +244,39 @@ class Solution:
```
Go
> 未精简版本
```go
func nextGreaterElement(nums1 []int, nums2 []int) []int {
res := make([]int, len(nums1))
for i := range res { res[i] = -1 }
m := make(map[int]int, len(nums1))
for k, v := range nums1 { m[v] = k }
stack := []int{0}
for i := 1; i < len(nums2); i++ {
top := stack[len(stack)-1]
if nums2[i] < nums2[top] {
stack = append(stack, i)
} else if nums2[i] == nums2[top] {
stack = append(stack, i)
} else {
for len(stack) != 0 && nums2[i] > nums2[top] {
if v, ok := m[nums2[top]]; ok {
res[v] = nums2[i]
}
stack = stack[:len(stack)-1]
if len(stack) != 0 {
top = stack[len(stack)-1]
}
}
stack = append(stack, i)
}
}
return res
}
```
> 精简版本
```go
func nextGreaterElement(nums1 []int, nums2 []int) []int {
res := make([]int, len(nums1))
@ -299,5 +332,36 @@ var nextGreaterElement = function (nums1, nums2) {
};
```
TypeScript
```typescript
function nextGreaterElement(nums1: number[], nums2: number[]): number[] {
const resArr: number[] = new Array(nums1.length).fill(-1);
const stack: number[] = [];
const helperMap: Map<number, number> = new Map();
nums1.forEach((num, index) => {
helperMap.set(num, index);
})
stack.push(0);
for (let i = 1, length = nums2.length; i < length; i++) {
let top = stack[stack.length - 1];
while (stack.length > 0 && nums2[top] < nums2[i]) {
let index = helperMap.get(nums2[top]);
if (index !== undefined) {
resArr[index] = nums2[i];
}
stack.pop();
top = stack[stack.length - 1];
}
if (helperMap.get(nums2[i]) !== undefined) {
stack.push(i);
}
}
return resArr;
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -182,5 +182,31 @@ var nextGreaterElements = function (nums) {
return res;
};
```
TypeScript
```typescript
function nextGreaterElements(nums: number[]): number[] {
const length: number = nums.length;
const stack: number[] = [];
stack.push(0);
const resArr: number[] = new Array(length).fill(-1);
for (let i = 1; i < length * 2; i++) {
const index = i % length;
let top = stack[stack.length - 1];
while (stack.length > 0 && nums[top] < nums[index]) {
resArr[top] = nums[index];
stack.pop();
top = stack[stack.length - 1];
}
if (i < length) {
stack.push(i);
}
}
return resArr;
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -245,7 +245,29 @@ var fib = function(n) {
};
```
TypeScript
```typescript
function fib(n: number): number {
/**
dp[i]: 第i个斐波那契数
dp[0]: 0;
dp[1]1
...
dp[i] = dp[i - 1] + dp[i - 2];
*/
const dp: number[] = [];
dp[0] = 0;
dp[1] = 1;
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
};
```
### C
动态规划:
```c
int fib(int n){

View File

@ -186,29 +186,28 @@ class Solution:
Go
```Go
func longestPalindromeSubseq(s string) int {
lenth:=len(s)
dp:=make([][]int,lenth)
for i:=0;i<lenth;i++{
for j:=0;j<lenth;j++{
if dp[i]==nil{
dp[i]=make([]int,lenth)
}
if i==j{
dp[i][j]=1
size := len(s)
max := func(a, b int) int {
if a > b {
return a
}
return b
}
dp := make([][]int, size)
for i := 0; i < size; i++ {
dp[i] = make([]int, size)
dp[i][i] = 1
}
for i := size - 1; i >= 0; i-- {
for j := i + 1; j < size; j++ {
if s[i] == s[j] {
dp[i][j] = dp[i+1][j-1] + 2
} else {
dp[i][j] = max(dp[i][j-1], dp[i+1][j])
}
}
}
for i:=lenth-1;i>=0;i--{
for j:=i+1;j<lenth;j++{
if s[i]==s[j]{
dp[i][j]=dp[i+1][j-1]+2
}else {
dp[i][j]=max(dp[i+1][j],dp[i][j-1])
}
}
}
return dp[0][lenth-1]
return dp[0][size-1]
}
```
@ -236,6 +235,35 @@ const longestPalindromeSubseq = (s) => {
};
```
TypeScript
```typescript
function longestPalindromeSubseq(s: string): number {
/**
dp[i][j][i,j]区间内,最长回文子序列的长度
*/
const length: number = s.length;
const dp: number[][] = new Array(length).fill(0)
.map(_ => new Array(length).fill(0));
for (let i = 0; i < length; i++) {
dp[i][i] = 1;
}
// 自下而上,自左往右遍历
for (let i = length - 1; i >= 0; i--) {
for (let j = i + 1; j < length; j++) {
if (s[i] === s[j]) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]);
}
}
}
return dp[0][length - 1];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -242,6 +242,22 @@ func change(amount int, coins []int) int {
}
```
Rust:
```rust
pub fn change(amount: i32, coins: Vec<i32>) -> i32 {
let amount = amount as usize;
let coins = coins.iter().map(|&c|c as usize).collect::<Vec<usize>>();
let mut dp = vec![0usize; amount + 1];
dp[0] = 1;
for i in 0..coins.len() {
for j in coins[i]..=amount {
dp[j] += dp[j - coins[i]];
}
}
dp[amount] as i32
}
```
Javascript
```javascript
const change = (amount, coins) => {
@ -258,6 +274,21 @@ const change = (amount, coins) => {
}
```
TypeScript
```typescript
function change(amount: number, coins: number[]): number {
const dp: number[] = new Array(amount + 1).fill(0);
dp[0] = 1;
for (let i = 0, length = coins.length; i < length; i++) {
for (let j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
};
```
-----------------------

View File

@ -347,6 +347,47 @@ public class Solution
}
}
```
Scala:
版本一: (正常解法)
```scala
object Solution {
def reverseStr(s: String, k: Int): String = {
val res = s.toCharArray // 转换为Array好处理
for (i <- s.indices by 2 * k) {
// 如果i+k大于了res的长度则需要全部翻转
if (i + k > res.length) {
reverse(res, i, s.length - 1)
} else {
reverse(res, i, i + k - 1)
}
}
new String(res)
}
// 翻转字符串从start到end
def reverse(s: Array[Char], start: Int, end: Int): Unit = {
var (left, right) = (start, end)
while (left < right) {
var tmp = s(left)
s(left) = s(right)
s(right) = tmp
left += 1
right -= 1
}
}
}
```
版本二: 首先利用sliding每隔k个进行分割随后转换为数组再使用zipWithIndex添加每个数组的索引紧接着利用map做变换如果索引%2==0则说明需要翻转否则原封不动最后再转换为String
```scala
object Solution {
def reverseStr(s: String, k: Int): String = {
s.sliding(k, k)
.toArray
.zipWithIndex
.map(v => if (v._2 % 2 == 0) v._1.reverse else v._1)
.mkString
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -229,6 +229,67 @@ const minDistance = (word1, word2) => {
};
```
TypeScript
> dp版本一
```typescript
function minDistance(word1: string, word2: string): number {
/**
dp[i][j]: word1前i个字符word2前j个字符所需最小步数
dp[0][0]=0: word1前0个字符为'', word2前0个字符为''
*/
const length1: number = word1.length,
length2: number = word2.length;
const dp: number[][] = new Array(length1 + 1).fill(0)
.map(_ => new Array(length2 + 1).fill(0));
for (let i = 0; i <= length1; i++) {
dp[i][0] = i;
}
for (let i = 0; i <= length2; i++) {
dp[0][i] = i;
}
for (let i = 1; i <= length1; i++) {
for (let j = 1; j <= length2; j++) {
if (word1[i - 1] === word2[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[length1][length2];
};
```
> dp版本二
```typescript
function minDistance(word1: string, word2: string): number {
/**
dp[i][j]: word1前i个字符word2前j个字符最长公共子序列的长度
dp[0][0]=0: word1前0个字符为'', word2前0个字符为''
*/
const length1: number = word1.length,
length2: number = word2.length;
const dp: number[][] = new Array(length1 + 1).fill(0)
.map(_ => new Array(length2 + 1).fill(0));
for (let i = 1; i <= length1; i++) {
for (let j = 1; j <= length2; j++) {
if (word1[i - 1] === word2[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]);
}
}
}
const maxLen: number = dp[length1][length2];
return length1 + length2 - maxLen * 2;
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -406,6 +406,63 @@ const countSubstrings = (s) => {
}
```
TypeScript
> 动态规划:
```typescript
function countSubstrings(s: string): number {
/**
dp[i][j]: [i,j]区间内的字符串是否为回文(左闭右闭)
*/
const length: number = s.length;
const dp: boolean[][] = new Array(length).fill(0)
.map(_ => new Array(length).fill(false));
let resCount: number = 0;
// 自下而上,自左向右遍历
for (let i = length - 1; i >= 0; i--) {
for (let j = i; j < length; j++) {
if (
s[i] === s[j] &&
(j - i <= 1 || dp[i + 1][j - 1] === true)
) {
dp[i][j] = true;
resCount++;
}
}
}
return resCount;
};
```
> 双指针法:
```typescript
function countSubstrings(s: string): number {
const length: number = s.length;
let resCount: number = 0;
for (let i = 0; i < length; i++) {
resCount += expandRange(s, i, i);
resCount += expandRange(s, i, i + 1);
}
return resCount;
};
function expandRange(s: string, left: number, right: number): number {
let palindromeNum: number = 0;
while (
left >= 0 && right < s.length &&
s[left] === s[right]
) {
palindromeNum++;
left--;
right++;
}
return palindromeNum;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -218,6 +218,7 @@ class Solution:
return result
```
> 贪心法:
```python
class Solution:
@ -276,6 +277,24 @@ func findLengthOfLCIS(nums []int) int {
}
```
Rust:
```rust
pub fn find_length_of_lcis(nums: Vec<i32>) -> i32 {
if nums.is_empty() {
return 0;
}
let mut result = 1;
let mut dp = vec![1; nums.len()];
for i in 1..nums.len() {
if nums[i - 1] < nums[i] {
dp[i] = dp[i - 1] + 1;
result = result.max(dp[i]);
}
}
result
}
```
Javascript
> 动态规划:
@ -319,6 +338,45 @@ const findLengthOfLCIS = (nums) => {
};
```
TypeScript
> 动态规划:
```typescript
function findLengthOfLCIS(nums: number[]): number {
/**
dp[i]: 前i个元素以nums[i]结尾,最长连续子序列的长度
*/
const dp: number[] = new Array(nums.length).fill(1);
let resMax: number = 1;
for (let i = 1, length = nums.length; i < length; i++) {
if (nums[i] > nums[i - 1]) {
dp[i] = dp[i - 1] + 1;
}
resMax = Math.max(resMax, dp[i]);
}
return resMax;
};
```
> 贪心:
```typescript
function findLengthOfLCIS(nums: number[]): number {
let resMax: number = 1;
let count: number = 1;
for (let i = 0, length = nums.length; i < length - 1; i++) {
if (nums[i] < nums[i + 1]) {
count++;
} else {
count = 1;
}
resMax = Math.max(resMax, count);
}
return resMax;
};
```

View File

@ -279,7 +279,7 @@ class Solution:
root.right = self.insertIntoBST(root.right, val)
# 返回更新后的以当前root为根节点的新树
return roo
return root
```
**递归法** - 无返回值

View File

@ -36,6 +36,8 @@
## 思路
为了易于大家理解,我还录制了视频,可以看这里:[手把手带你撕出正确的二分法](https://www.bilibili.com/video/BV1fA4y1o715)
**这道题目的前提是数组为有序数组**,同时题目还强调**数组中无重复元素**,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。
二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。例如到底是 `while(left < right)` 还是 `while(left <= right)`,到底是`right = middle`呢,还是要`right = middle - 1`呢?
@ -612,5 +614,81 @@ public class Solution{
```
**Kotlin:**
```Kotlin
// (版本一)左闭右开区间
class Solution {
fun search(nums: IntArray, target: Int): Int {
var left = 0
var right = nums.size // [left,right) 右侧为开区间right 设置为 nums.size
while (left < right) {
val mid = (left + right) / 2
if (nums[mid] < target) left = mid + 1
else if (nums[mid] > target) right = mid // 代码的核心,循环中 right 是开区间,这里也应是开区间
else return mid
}
return -1 // 没有找到 target ,返回 -1
}
}
// (版本二)左闭右闭区间
class Solution {
fun search(nums: IntArray, target: Int): Int {
var left = 0
var right = nums.size - 1 // [left,right] 右侧为闭区间right 设置为 nums.size - 1
while (left <= right) {
val mid = (left + right) / 2
if (nums[mid] < target) left = mid + 1
else if (nums[mid] > target) right = mid - 1 // 代码的核心,循环中 right 是闭区间,这里也应是闭区间
else return mid
}
return -1 // 没有找到 target ,返回 -1
}
}
```
**Scala:**
(版本一)左闭右闭区间
```scala
object Solution {
def search(nums: Array[Int], target: Int): Int = {
var left = 0
var right = nums.length - 1
while (left <= right) {
var mid = left + ((right - left) / 2)
if (target == nums(mid)) {
return mid
} else if (target < nums(mid)) {
right = mid - 1
} else {
left = mid + 1
}
}
-1
}
}
```
(版本二)左闭右开区间
```scala
object Solution {
def search(nums: Array[Int], target: Int): Int = {
var left = 0
var right = nums.length
while (left < right) {
val mid = left + (right - left) / 2
if (target == nums(mid)) {
return mid
} else if (target < nums(mid)) {
right = mid
} else {
left = mid + 1
}
}
-1
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -1154,7 +1154,75 @@ class MyLinkedList {
}
```
Scala:
```scala
class ListNode(_x: Int = 0, _next: ListNode = null) {
var next: ListNode = _next
var x: Int = _x
}
class MyLinkedList() {
var size = 0 // 链表尺寸
var dummy: ListNode = new ListNode(0) // 虚拟头节点
// 获取第index个节点的值
def get(index: Int): Int = {
if (index < 0 || index >= size) {
return -1;
}
var cur = dummy
for (i <- 0 to index) {
cur = cur.next
}
cur.x // 返回cur的值
}
// 在链表最前面插入一个节点
def addAtHead(`val`: Int) {
addAtIndex(0, `val`)
}
// 在链表最后面插入一个节点
def addAtTail(`val`: Int) {
addAtIndex(size, `val`)
}
// 在第index个节点之前插入一个新节点
// 如果index等于链表长度则说明新插入的节点是尾巴
// 如果index等于0则说明新插入的节点是头
// 如果index>链表长度,则说明为空
def addAtIndex(index: Int, `val`: Int) {
if (index > size) {
return
}
var loc = index // 因为参数index是val不可变类型所以需要赋值给一个可变类型
if (index < 0) {
loc = 0
}
size += 1 //链表尺寸+1
var pre = dummy
for (i <- 0 until loc) {
pre = pre.next
}
val node: ListNode = new ListNode(`val`, pre.next)
pre.next = node
}
// 删除第index个节点
def deleteAtIndex(index: Int) {
if (index < 0 || index >= size) {
return
}
size -= 1
var pre = dummy
for (i <- 0 until index) {
pre = pre.next
}
pre.next = pre.next.next
}
}
```
-----------------------

View File

@ -200,6 +200,29 @@ const maxProfit = (prices,fee) => {
}
```
TypeScript
```typescript
function maxProfit(prices: number[], fee: number): number {
/**
dp[i][0]:持有股票
dp[i][1]: 不持有
*/
const length: number = prices.length;
if (length === 0) return 0;
const dp: number[][] = new Array(length).fill(0).map(_ => []);
dp[0][0] = -prices[0];
dp[0][1] = 0;
for (let i = 1; i < 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[length - 1][1];
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -297,6 +297,56 @@ const findLength = (nums1, nums2) => {
}
```
TypeScript
> 动态规划:
```typescript
function findLength(nums1: number[], nums2: number[]): number {
/**
dp[i][j]nums[i-1]和nums[j-1]结尾,最长重复子数组的长度
*/
const length1: number = nums1.length,
length2: number = nums2.length;
const dp: number[][] = new Array(length1 + 1).fill(0)
.map(_ => new Array(length2 + 1).fill(0));
let resMax: number = 0;
for (let i = 1; i <= length1; i++) {
for (let j = 1; j <= length2; j++) {
if (nums1[i - 1] === nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
resMax = Math.max(resMax, dp[i][j]);
}
}
}
return resMax;
};
```
> 滚动数组:
```typescript
function findLength(nums1: number[], nums2: number[]): number {
const length1: number = nums1.length,
length2: number = nums2.length;
const dp: number[] = new Array(length1 + 1).fill(0);
let resMax: number = 0;
for (let i = 1; i <= length1; i++) {
for (let j = length2; j >= 1; j--) {
if (nums1[i - 1] === nums2[j - 1]) {
dp[j] = dp[j - 1] + 1;
resMax = Math.max(resMax, dp[j]);
} else {
dp[j] = 0;
}
}
}
return resMax;
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -34,7 +34,8 @@
那么单调栈的原理是什么呢为什么时间复杂度是O(n)就可以找到每一个元素的右边第一个比它大的元素位置呢?
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素的元素,优点是只需要遍历一次。
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是只需要遍历一次。
在使用单调栈的时候首先要明确如下几点:
@ -192,7 +193,7 @@ class Solution {
否则的话,可以直接入栈。
注意,单调栈里 加入的元素是 下标。
*/
Stack<Integer>stack=new Stack<>();
Deque<Integer> stack=new LinkedList<>();
stack.push(0);
for(int i=1;i<lens;i++){
@ -216,7 +217,7 @@ class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int lens=temperatures.length;
int []res=new int[lens];
Stack<Integer>stack=new Stack<>();
Deque<Integer> stack=new LinkedList<>();
for(int i=0;i<lens;i++){
while(!stack.isEmpty()&&temperatures[i]>temperatures[stack.peek()]){
@ -233,7 +234,7 @@ class Solution {
}
```
Python
``` Python3
```python
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
answer = [0]*len(temperatures)
@ -277,8 +278,36 @@ func dailyTemperatures(t []int) []int {
}
```
> 单调栈法
> 单调栈法(未精简版本)
```go
func dailyTemperatures(temperatures []int) []int {
res := make([]int, len(temperatures))
// 初始化栈顶元素为第一个下标索引0
stack := []int{0}
for i := 1; i < len(temperatures); i++ {
top := stack[len(stack)-1]
if temperatures[i] < temperatures[top] {
stack = append(stack, i)
} else if temperatures[i] == temperatures[top] {
stack = append(stack, i)
} else {
for len(stack) != 0 && temperatures[i] > temperatures[top] {
res[top] = i - top
stack = stack[:len(stack)-1]
if len(stack) != 0 {
top = stack[len(stack)-1]
}
}
stack = append(stack, i)
}
}
return res
}
```
> 单调栈法(精简版本)
```go
// 单调递减栈
func dailyTemperatures(num []int) []int {
@ -343,6 +372,32 @@ var dailyTemperatures = function(temperatures) {
};
```
TypeScript:
> 精简版:
```typescript
function dailyTemperatures(temperatures: number[]): number[] {
const length: number = temperatures.length;
const stack: number[] = [];
const resArr: number[] = new Array(length).fill(0);
stack.push(0);
for (let i = 1; i < length; i++) {
let top = stack[stack.length - 1];
while (
stack.length > 0 &&
temperatures[top] < temperatures[i]
) {
resArr[top] = i - top;
stack.pop();
top = stack[stack.length - 1];
}
stack.push(i);
}
return resArr;
};
```

View File

@ -266,7 +266,30 @@ var minCostClimbingStairs = function(cost) {
};
```
### TypeScript
```typescript
function minCostClimbingStairs(cost: number[]): number {
/**
dp[i]: 走到第i阶需要花费的最少金钱
dp[0]: cost[0];
dp[1]: cost[1];
...
dp[i]: min(dp[i - 1], dp[i - 2]) + cost[i];
*/
const dp: number[] = [];
const length: number = cost.length;
dp[0] = cost[0];
dp[1] = cost[1];
for (let i = 2; i <= length; i++) {
dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
}
return Math.min(dp[length - 1], dp[length - 2]);
};
```
### C
```c
int minCostClimbingStairs(int* cost, int costSize){
//开辟dp数组大小为costSize

View File

@ -158,6 +158,71 @@ class Solution {
return list;
}
}
class Solution{
/*解法二: 上述c++补充思路的Java代码实现*/
public int[][] findPartitions(String s) {
List<Integer> temp = new ArrayList<>();
int[][] hash = new int[26][2];//26个字母2列 表示该字母对应的区间
for (int i = 0; i < s.length(); i++) {
//更新字符c对应的位置i
char c = s.charAt(i);
if (hash[c - 'a'][0] == 0) hash[c - 'a'][0] = i;
hash[c - 'a'][1] = i;
//第一个元素区别对待一下
hash[s.charAt(0) - 'a'][0] = 0;
}
List<List<Integer>> h = new LinkedList<>();
//组装区间
for (int i = 0; i < 26; i++) {
//if (hash[i][0] != hash[i][1]) {
temp.clear();
temp.add(hash[i][0]);
temp.add(hash[i][1]);
//System.out.println(temp);
h.add(new ArrayList<>(temp));
// }
}
// System.out.println(h);
// System.out.println(h.size());
int[][] res = new int[h.size()][2];
for (int i = 0; i < h.size(); i++) {
List<Integer> list = h.get(i);
res[i][0] = list.get(0);
res[i][1] = list.get(1);
}
return res;
}
public List<Integer> partitionLabels(String s) {
int[][] partitions = findPartitions(s);
List<Integer> res = new ArrayList<>();
Arrays.sort(partitions, (o1, o2) -> Integer.compare(o1[0], o2[0]));
int right = partitions[0][1];
int left = 0;
for (int i = 0; i < partitions.length; i++) {
if (partitions[i][0] > right) {
//左边界大于右边界即可纪委一次分割
res.add(right - left + 1);
left = partitions[i][0];
}
right = Math.max(right, partitions[i][1]);
}
//最右端
res.add(right - left + 1);
return res;
}
}
```
### Python

View File

@ -23,6 +23,8 @@
# 思路
为了易于大家理解,我还特意录制了视频,[本题视频讲解](https://www.bilibili.com/video/BV1QB4y1D7ep)
## 暴力排序
最直观的想法,莫过于:每个数平方之后,排个序,美滋滋,代码如下:
@ -359,6 +361,64 @@ class Solution {
}
```
Kotlin:
```kotlin
class Solution {
// 双指针法
fun sortedSquares(nums: IntArray): IntArray {
var res = IntArray(nums.size)
var left = 0 // 指向数组的最左端
var right = nums.size - 1 // 指向数组端最右端
// 选择平方数更大的那一个往 res 数组中倒序填充
for (index in nums.size - 1 downTo 0) {
if (nums[left] * nums[left] > nums[right] * nums[right]) {
res[index] = nums[left] * nums[left]
left++
} else {
res[index] = nums[right] * nums[right]
right--
}
}
return res
}
}
```
Scala:
双指针:
```scala
object Solution {
def sortedSquares(nums: Array[Int]): Array[Int] = {
val res: Array[Int] = new Array[Int](nums.length)
var top = nums.length - 1
var i = 0
var j = nums.length - 1
while (i <= j) {
if (nums(i) * nums(i) <= nums(j) * nums(j)) {
// 当左侧平方小于等于右侧res数组顶部放右侧的平方并且top下移j左移
res(top) = nums(j) * nums(j)
top -= 1
j -= 1
} else {
// 当左侧平方大于右侧res数组顶部放左侧的平方并且top下移i右移
res(top) = nums(i) * nums(i)
top -= 1
i += 1
}
}
res
}
}
```
骚操作(暴力思路):
```scala
object Solution {
def sortedSquares(nums: Array[Int]): Array[Int] = {
nums.map(x=>{x*x}).sortWith(_ < _)
}
}
```
-----------------------

Some files were not shown because too many files have changed in this diff Show More