Merge branch 'master' into master

This commit is contained in:
程序员Carl
2022-06-11 09:06:04 +08:00
committed by GitHub
63 changed files with 2921 additions and 133 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

@ -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,10 +77,20 @@ public:
双指针法(快慢指针法): **通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。**
定义快慢指针
* 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
* 慢指针:指向更新 新数组下标的位置
很多同学这道题目做的很懵,就是不理解 快慢指针究竟都是什么含义,所以一定要明确含义,后面的思路就更容易理解了。
删除过程如下:
![27.移除元素-双指针法](https://tva1.sinaimg.cn/large/008eGmZEly1gntrds6r59g30du09mnpd.gif)
很多同学不了解
**双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。**
后续都会一一介绍到,本题代码如下:
@ -104,8 +116,6 @@ public:
* 时间复杂度O(n)
* 空间复杂度O(1)
旧文链接:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)
```CPP
/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
@ -329,6 +339,7 @@ int removeElement(int* nums, int numsSize, int val){
}
```
Kotlin:
```kotlin
fun removeElement(nums: IntArray, `val`: Int): Int {
@ -340,5 +351,22 @@ fun removeElement(nums: IntArray, `val`: Int): Int {
}
```
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,7 +316,26 @@ 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

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

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;

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;

View File

@ -318,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
}
```
**此时我们就掌握了二叉树的层序遍历了,那么如下九道力扣上的题目,只需要修改模板的两三行代码(不能再多了),便可打倒!**
@ -548,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/)
@ -770,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/)
@ -1001,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叉树的层序遍历
@ -1245,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/)
@ -1453,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/)
@ -1712,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/)
@ -1963,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/)
@ -2180,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/)
@ -2399,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叉树的最大深度

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,69 @@ func minDepth(_ root: TreeNode?) -> Int {
}
```
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

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

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

@ -385,5 +385,61 @@ 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

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

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

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

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

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

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

@ -363,5 +363,87 @@ 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

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

@ -318,5 +318,69 @@ 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

@ -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)
size := len(s)
max := func(a, b int) int {
if a > b {
return a
}
if i==j{
dp[i][j]=1
return b
}
dp := make([][]int, size)
for i := 0; i < size; i++ {
dp[i] = make([]int, size)
dp[i][i] = 1
}
}
for i:=lenth-1;i>=0;i--{
for j:=i+1;j<lenth;j++{
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+1][j],dp[i][j-1])
dp[i][j] = max(dp[i][j-1], dp[i+1][j])
}
}
}
return dp[0][lenth-1]
return dp[0][size-1]
}
```

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

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

@ -36,6 +36,8 @@
## 思路
为了易于大家理解,我还录制了视频,可以看这里:[手把手带你撕出正确的二分法](https://www.bilibili.com/video/BV1fA4y1o715)
**这道题目的前提是数组为有序数组**,同时题目还强调**数组中无重复元素**,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。
二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。例如到底是 `while(left < right)` 还是 `while(left <= right)`,到底是`right = middle`呢,还是要`right = middle - 1`呢?
@ -611,6 +613,8 @@ public class Solution{
}
```
**Kotlin:**
```Kotlin
// (版本一)左闭右开区间
@ -642,6 +646,48 @@ class Solution {
}
}
```
**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
}
}
```
-----------------------

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()]){

View File

@ -23,6 +23,8 @@
# 思路
为了易于大家理解,我还特意录制了视频,[本题视频讲解](https://www.bilibili.com/video/BV1QB4y1D7ep)
## 暴力排序
最直观的想法,莫过于:每个数平方之后,排个序,美滋滋,代码如下:

View File

@ -418,6 +418,38 @@ char ** commonChars(char ** words, int wordsSize, int* returnSize){
return ret;
}
```
Scala:
```scala
object Solution {
def commonChars(words: Array[String]): List[String] = {
// 声明返回结果的不可变List集合因为res要重新赋值所以声明为var
var res = List[String]()
var hash = new Array[Int](26) // 统计字符出现的最小频率
// 统计第一个字符串中字符出现的次数
for (i <- 0 until words(0).length) {
hash(words(0)(i) - 'a') += 1
}
// 统计其他字符串出现的频率
for (i <- 1 until words.length) {
// 统计其他字符出现的频率
var hashOtherStr = new Array[Int](26)
for (j <- 0 until words(i).length) {
hashOtherStr(words(i)(j) - 'a') += 1
}
// 更新hash取26个字母最小出现的频率
for (k <- 0 until 26) {
hash(k) = math.min(hash(k), hashOtherStr(k))
}
}
// 根据hash的结果转换输出的形式
for (i <- 0 until 26) {
for (j <- 0 until hash(i)) {
res = res :+ (i + 'a').toChar.toString
}
}
res
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -374,6 +374,27 @@ func removeDuplicates(_ s: String) -> String {
return String(stack)
}
```
Scala:
```scala
object Solution {
import scala.collection.mutable
def removeDuplicates(s: String): String = {
var stack = mutable.Stack[Int]()
var str = "" // 保存最终结果
for (i <- s.indices) {
var tmp = s(i)
// 如果栈非空并且栈顶元素等于当前字符,那么删掉栈顶和字符串最后一个元素
if (!stack.isEmpty && tmp == stack.head) {
str = str.take(str.length - 1)
stack.pop()
} else {
stack.push(tmp)
str += tmp
}
}
str
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

312
problems/qita/gitserver.md Normal file
View File

@ -0,0 +1,312 @@
# 一文手把手教你搭建Git私服
## 为什么要搭建Git私服
很多同学都问文章文档资料怎么备份啊自己电脑和公司电脑怎么随时同步资料啊等等这里呢我写一个搭建自己的git私服的详细教程
为什么要搭建一个Git私服呢而不是用Github免费的私有仓库有以下几点
* Github 私有仓库真的慢文件一旦多了或者有图片文件git pull 的时候半天拉不下来
* 自己的文档难免有自己个人信息放在github心里也是担心的
* 想建几个库就建几个,想几个人合作开发都可以,不香么?
**网上可以搜到很多git搭建但是说的模棱两可**而且有的直接是在本地搭建git服务既然是备份搭建在本地哪有备份的意义一定要有一个远端服务器 而且自己的电脑和公司的电脑还是同步自己的文章,文档和资料等等。
适合人群: 想通过git私服来备份自己的文章Markdown并做版本管理的同学
最后,写好每篇 Chat 是对我的责任,也是对你的尊重。谢谢大家~
正文如下:
-----------------------------
## 如何找到可以外网访问服务器
有的同学问了,自己的电脑就不能作为服务器么?
这里要说一下安装家庭带宽运营商默认是不会给我们独立分配公网IP的
一般情况下是一片区域公用一个公网IP池所以外网是不能访问到在家里我们使用的电脑的
除非我们自己去做映射这其实非常麻烦而且公网IP池 是不断变化的
辛辛苦苦做了映射运营商给IP一换我们的努力就白扯了
那我们如何才能找到一个外网可以访问的服务器呢,此时云计算拯救了我们。
推荐大家选一家云厂商(阿里云,腾讯云,百度云都可以)在上面上买一台云服务器
* [阿里云活动期间服务器购买](https://www.aliyun.com/minisite/goods?taskCode=shareNew2205&recordId=3641992&userCode=roof0wob)
* [腾讯云活动期间服务器购买](https://curl.qcloud.com/EiaMXllu)
云厂商经常做活动,如果从来没有买过云服务器的账号更便宜,低配一年一百块左右的样子,强烈推荐一起买个三年。
买云服务器的时候推荐直接安装centos系统。
这里要说一下,有了自己的云服务器之后 不仅仅可以用来做git私服
**同时还可以做网站,做程序后台,跑程序,做测试**(这样我们自己的电脑就不会因为自己各种搭建环境下载各种包而搞的的烂糟糟),等等等。
有自己云服务器和一个公网IP真的是一件非常非常幸福的事情能体验到自己的服务随时可以部署上去提供给所有人使用的喜悦。
外网可以访问的服务器解决了接下来就要部署git服务了
本文将采用centos系统来部署git私服
## 服务器端安装Git
切换至root账户
```
su root
```
看一下服务器有没有安装git如果出现下面信息就说明是有git的
```
[root@instance-5fcyjde7 ~]# git
usage: git [--version] [--help] [-c name=value]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]
The most commonly used git commands are:
add Add file contents to the index
bisect Find by binary search the change that introduced a bug
branch List, create, or delete branches
checkout Checkout a branch or paths to the working tree
clone Clone a repository into a new directory
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
fetch Download objects and refs from another repository
grep Print lines matching a pattern
init Create an empty Git repository or reinitialize an existing one
log Show commit logs
merge Join two or more development histories together
mv Move or rename a file, a directory, or a symlink
pull Fetch from and merge with another repository or a local branch
push Update remote refs along with associated objects
rebase Forward-port local commits to the updated upstream head
reset Reset current HEAD to the specified state
rm Remove files from the working tree and from the index
show Show various types of objects
status Show the working tree status
tag Create, list, delete or verify a tag object signed with GPG
'git help -a' and 'git help -g' lists available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
```
如果没有git就安装一下yum安装的版本默认是 `1.8.3.1`
```
yum install git
```
安装成功之后,看一下自己安装的版本
```
git --version
```
## 服务器端设置Git账户
创建一个git的linux账户这个账户只做git私服的操作也是为了安全起见
如果不新创建一个linux账户在自己的常用的linux账户下创建的话哪天手抖 来一个`rm -rf *` 操作 数据可全没了
**这里linux git账户的密码设置的尽量复杂一些我这里为了演示就设置成为'gitpassword'**
```
adduser git
passwd gitpassword
```
然后就要切换成git账户进行后面的操作了
```
[root@instance-5fcyjde7 ~]# su - git
```
看一下自己所在的目录是不是在git目录下面
```
[git@instance-5fcyjde7 ~]$ pwd
/home/git
```
## 服务器端密钥管理
创建`.ssh` 目录,如果`.ssh` 已经存在了,可以忽略这一项
为啥用配置ssh公钥呢同学们记不记得我急使用github上传上传代码的时候也要把自己的公钥配置上github上
这也是方面每次操作git仓库的时候不用再去输入密码
```
cd ~/
mkdir .ssh
```
进入.ssh 文件下,创建一个 `authorized_keys` 文件,这个文件就是后面就是要放我们客户端的公钥
```
cd ~/.ssh
touch authorized_keys
```
别忘了`authorized_keys`给设置权限,很多同学发现自己不能免密登陆,都是因为忘记了给`authorized_keys` 设置权限
```
chmod 700 /home/git/.ssh
chmod 600 /home/git/.ssh/authorized_keys
```
接下来我们要把客户端的公钥放在git服务器上我们在回到客户端创建一个公钥
在我们自己的电脑上,有公钥和私钥 两个文件分别是:`id_rsa``id_rsa.pub`
如果是`windows`系统公钥私钥的目录在`C:\Users\用户名\.ssh`
如果是mac 或者 linux 公钥和私钥的目录这里 `cd ~/.ssh/` 如果发现自己的电脑上没有公钥私钥,那就自己创建一个
创建密钥的命令
```
ssh-keygen -t rsa
```
创建密钥的过程中,一路点击回车就可以了。不需要填任何东西
把公钥拷贝到git服务器上将我们刚刚生成的`id_rsa.pub`拷贝到git服务器的`/home/git/.ssh/`目录
在git服务器上将公钥添加到`authorized_keys` 文件中
```
cd /home/git/.ssh/
cat id_rsa.pub >> authorized_keys
```
如何看我们配置的密钥是否成功呢, 在客户点直接登录git服务器看看是否是免密登陆
```
ssh git@git服务器ip
```
例如:
```
ssh git@127.0.0.1
```
如果可以免密登录,那就说明服务器端密钥配置成功了
## 服务器端部署Git 仓库
我们在登陆到git 服务器端,切换为成 git账户
如果是root账户切换成git账户
```
su - git
```
如果是其他账户切换为git账户
```
sudo su - git
```
进入git目录下
```
cd ~/git
```
创建我们的第一个Git私服的仓库我们叫它为world仓库
那么首先创建一个文件夹名为: world.git ,然后进入这个目录
有同学问,为什么文件夹名字后面要放`.git` 其实不这样命名也是可以的
但是细心的同学可能注意到我们平时在github上 `git clone` 其他人的仓库的时候,仓库名字后面,都是加上`.git`
例如下面这个例子其实就是github对仓库名称的一个命名规则所以我们也遵守github的命名规则。
```
git clone https://github.com/youngyangyang04/NoSQLAttack.git
```
所以我们的操作是
```
[git@localhost git]# mkdir world.git
[git@localhost git]# cd world.git
```
初始化我们的`world`仓库
```
git init --bare
```
**如果我们想创建多个仓库就在这里创建多个文件夹并初始化就可以了和world仓库的操作过程是一样一样的**
现在我们服务端的git仓库就部署完了接下来就看看客户端如何使用这个仓库呢
## 客户端连接远程仓库
我们在自己的电脑上创建一个文件夹 也叫做`world`
其实这里命名是随意的但是我们为了和git服务端的仓库名称保持同步。 这样更直观我们操作的是哪一个仓库。
```
mkdir world
cd world
```
进入world文件并初始化操作
```
cd world
git init
```
在world目录上创建一个测试文件并且将其添加到git版本管理中
```
touch test
git add test
git commit -m "add test file"
```
将次仓库和远端仓库同步
```
git remote add origin git@git服务器端的ip:world.git
git push -u origin master
```
此时这个test测试文件就已经提交到我们的git远端私服上了
## Git私服安全问题
这里有两点安全问题
### linux git的密码不要泄露出去
否则,别人可以通过 ssh git@git服务器IP 来登陆到你的git私服服务器上
当然了,这里同学们如果买的是云厂商的云服务器的话
如果有人恶意想通过 尝试不同密码链接的方式来链接你的服务器,重试三次以上
这个客户端的IP就会被封掉同时邮件通知我们可以IP来自哪里
所以大可放心 密码只要我们不泄露出去基本上不会有人同时不断尝试密码的方式来登上我们的git私服服务器
### 私钥文件`id_rsa` 不要给别人
如果有人得到了这个私钥就可以免密码登陆我们的git私服上了我相信大家也不至于把自己的私钥主动给别人吧
## 总结
这里就是整个git私服搭建的全过程安全问题我也给大家列举了出来接下来好好享受自己的Git私服吧
**enjoy!**

126
problems/qita/server.md Normal file
View File

@ -0,0 +1,126 @@
# 一台服务器有什么用!
但在组织这场活动的时候,了解到大家都有一个共同的问题: **这个服务器究竟有啥用??**
这真是一个好问题,而且我一句两句还说不清楚,所以就专门发文来讲一讲。
同时我还录制的一期视频,哈哈我的视频号,大家可以关注一波。
一说到服务器,可能很多人都说搞分布式,做计算,搞爬虫,做程序后台服务,多人合作等等。
其实这些普通人都用不上,我来说一说大家能用上的吧。
## 搭建git私服
大家平时工作的时候一定有一个自己的工作文件夹,学生的话就是自己的课件,考试,准备面试的资料等等。
已经工作的录友会有一个文件夹放着自己重要的文档Markdown图片简历等等。
这么重要的文件夹,而且我们每天都要更新,也担心哪天电脑丢了,或者坏了,突然这些都不见了。
所以我们想备份嘛。
还有就是我们经常个人电脑和工作电脑要同步一些私人资料,而不是用微信传来传去。
这些都是git私服的使用场景而且很好用。
大家也知道 githubgitee也可以搞私人仓库 用来备份同步文件但自己的文档可能放着很多重要的信息包括自己的各种密码密钥之类的放到上面未必安全。你就不怕哪些重大bug把你的信息都泄漏了么[机智]
更关键的是github 和 gitee都限速的。毕竟人家的功能定位并不是网盘。
项目里有大文件几百M以上例如pdfppt等等 其上传和下载速度会让你窒息。
**后面我会发文专门来讲一讲如何大家git私服**
## 搞一个文件存储
这个可以用来生成文件的下载链接,也可以把本地文件传到服务器上。
相当于自己做一个对象存储,其实云厂商也有对象存储的产品。
不过我们自己也可以做一个,不够很多很同学应该都不知道对象存储怎么用吧,其实我们用服务器可以自己做一个类似的公司。
我现在就用自己用go写的一个工具部署在服务器上。 用来和服务器传文件,或者生成一些文件的临时下载链接。
这些都是直接命令行操作的,
操作方式这样,我把命令包 包装成一个shell命令想传那个文件直接 uploadtomyserver然后就返回可以下载的链接这个文件也同时传到了我的服务器上。
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211126165643.png)
我也把我的项目代码放在了github上
https://github.com/youngyangyang04/fileHttpServer
感兴趣的录友可以去学习一波顺便给个star 哈哈
## 网站
做网站,例如 大家知道用html 写几行代码,就可以生成一个网页,但怎么给别人展示呢?
大家如果用自己的电脑做服务器,只能同一个路由器下的设备可以访问你的网站,可能这个设备出了这个屋子 都访问不了你的网站了。
因为你的IP不是公网IP。
如果有了一台云服务器都是配公网IP你的网站就可以让任何人访问了。
或者说 你提供的一个服务就可以让任何人使用。
例如第二个例子中,我们可以自己开发一个文件存储,这个服务,我只把把命令行给其他人,其他人都可以使用我的服务来生成链接,当然他们的文件也都传到了我的服务器上。
再说一个使用场景。
我之前在组织免费里服务器的活动的时候阿里云给我一个excel让面就是从我这里买服务器录友的名单我直接把这个名单甩到群里让大家自己检查出现在名单里就可以找我返现这样做是不是也可以。
这么做有几个很大的问题:
* 大家都要去下载excel做对比会有人改excel的内容然后就说是从你这里买的我不可能挨个去比较excel有没有改动
* excel有其他人的个人信息这是不能暴漏的。
* 如果每个人自己用excel查询私信我返现一个将近两千人找我返现我微信根本处理不过来这就变成体力活了。
那应该怎么做呢,
我就简单写一个查询的页面后端逻辑就是读一个execel表格大家在查询页面输入自己的阿里云ID如果在excel里页面就会返回返现群的二维码大家就可以自主扫码加群了。
这样,我最后就直接在返现群里 发等额红包就好了,是不是极大降低人力成本了
当然我是把 17个返现群的二维码都生成好了按照一定的规则展现给查询通过的录友。
就是这样一个非常普通的查询页面。
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211126160200.png)
查询通过之后,就会展现返现群二维码。
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211127160558.png)
但要部署在服务器上因为没有公网IP别人用不了你的服务。
## 学习linux
学习linux其实在自己的电脑上搞一台虚拟机或者安装双系统也可以学习不过这很考验你的电脑性能如何了。
如果你有一个服务器,那就是独立的一台电脑,你怎么霍霍就怎么霍霍,而且一年都不用关机的,可以一直跑你的任务,和你本地电脑也完全隔离。
更方便的是你目前系统假如是centos想做一个实验需要在unbantu上如果是云服务器更换系统就是在 后台点一下,一键重装,云厂商基本都是支持所有系统一件安装的。
我们平时自己玩linux经常是配各种环境然后这个linux就被自己玩坏了一般都是毫无节制使用root权限导致的总之就是环境配不起来了基本就要重装了。
那云服务器重装系统可太方便了。
还有就是加入你好不容易配好的环境,如果以后把这个环境玩坏了,你先回退这之前配好的环境而不是重装系统在重新配一遍吧。
那么可以用云服务器的镜像保存功能,就是你配好环境的那一刻就可以打一个镜像包,以后如果环境坏了,直接回退到上次镜像包的状态,这是不是就很香了。
## 总结
其实云服务器还有很多其他用处,不过我就说一说大家普遍能用的上的。
* [阿里云活动期间服务器购买](https://www.aliyun.com/minisite/goods?taskCode=shareNew2205&recordId=3641992&userCode=roof0wob)
* [腾讯云活动期间服务器购买](https://curl.qcloud.com/EiaMXllu)

View File

@ -258,6 +258,13 @@ class TreeNode<T> {
}
}
```
Scala:
```scala
class TreeNode(_value: Int = 0, _left: TreeNode = null, _right: TreeNode = null) {
var value: Int = _value
var left: TreeNode = _left
var right: TreeNode = _right
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -591,6 +591,80 @@ function postorderTraversal(root: TreeNode | null): number[] {
return res;
};
```
Scala:
```scala
// 前序遍历
object Solution {
import scala.collection.mutable
def preorderTraversal(root: TreeNode): List[Int] = {
val res = mutable.ListBuffer[Int]()
val stack = mutable.Stack[TreeNode]()
if (root != null) stack.push(root)
while (!stack.isEmpty) {
var curNode = stack.top
if (curNode != null) {
stack.pop()
if (curNode.right != null) stack.push(curNode.right)
if (curNode.left != null) stack.push(curNode.left)
stack.push(curNode)
stack.push(null)
} else {
stack.pop()
res.append(stack.pop().value)
}
}
res.toList
}
}
// 中序遍历
object Solution {
import scala.collection.mutable
def inorderTraversal(root: TreeNode): List[Int] = {
val res = mutable.ListBuffer[Int]()
val stack = mutable.Stack[TreeNode]()
if (root != null) stack.push(root)
while (!stack.isEmpty) {
var curNode = stack.top
if (curNode != null) {
stack.pop()
if (curNode.right != null) stack.push(curNode.right)
stack.push(curNode)
stack.push(null)
if (curNode.left != null) stack.push(curNode.left)
} else {
// 等于空的时候好办,弹出这个元素
stack.pop()
res.append(stack.pop().value)
}
}
res.toList
}
}
// 后序遍历
object Solution {
import scala.collection.mutable
def postorderTraversal(root: TreeNode): List[Int] = {
val res = mutable.ListBuffer[Int]()
val stack = mutable.Stack[TreeNode]()
if (root != null) stack.push(root)
while (!stack.isEmpty) {
var curNode = stack.top
if (curNode != null) {
stack.pop()
stack.push(curNode)
stack.push(null)
if (curNode.right != null) stack.push(curNode.right)
if (curNode.left != null) stack.push(curNode.left)
} else {
stack.pop()
res.append(stack.pop().value)
}
}
res.toList
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -568,6 +568,71 @@ func inorderTraversal(_ root: TreeNode?) -> [Int] {
return result
}
```
Scala:
```scala
// 前序遍历(迭代法)
object Solution {
import scala.collection.mutable
def preorderTraversal(root: TreeNode): List[Int] = {
val res = mutable.ListBuffer[Int]()
if (root == null) return res.toList
// 声明一个栈泛型为TreeNode
val stack = mutable.Stack[TreeNode]()
stack.push(root) // 先把根节点压入栈
while (!stack.isEmpty) {
var curNode = stack.pop()
res.append(curNode.value) // 先把这个值压入栈
// 如果当前节点的左右节点不为空,则入栈,先放右节点,再放左节点
if (curNode.right != null) stack.push(curNode.right)
if (curNode.left != null) stack.push(curNode.left)
}
res.toList
}
}
// 中序遍历(迭代法)
object Solution {
import scala.collection.mutable
def inorderTraversal(root: TreeNode): List[Int] = {
val res = mutable.ArrayBuffer[Int]()
if (root == null) return res.toList
val stack = mutable.Stack[TreeNode]()
var curNode = root
// 将左节点都入栈当遍历到最左到空的时候再弹出栈顶元素加入res
// 再把栈顶元素的右节点加进来,继续下一轮遍历
while (curNode != null || !stack.isEmpty) {
if (curNode != null) {
stack.push(curNode)
curNode = curNode.left
} else {
curNode = stack.pop()
res.append(curNode.value)
curNode = curNode.right
}
}
res.toList
}
}
// 后序遍历(迭代法)
object Solution {
import scala.collection.mutable
def postorderTraversal(root: TreeNode): List[Int] = {
val res = mutable.ListBuffer[Int]()
if (root == null) return res.toList
val stack = mutable.Stack[TreeNode]()
stack.push(root)
while (!stack.isEmpty) {
val curNode = stack.pop()
res.append(curNode.value)
// 这次左节点先入栈,右节点再入栈
if(curNode.left != null) stack.push(curNode.left)
if(curNode.right != null) stack.push(curNode.right)
}
// 最后需要翻转List
res.reverse.toList
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -470,5 +470,56 @@ func postorder(_ root: TreeNode?, res: inout [Int]) {
res.append(root!.val)
}
```
Scala: 前序遍历144.二叉树的前序遍历)
```scala
object Solution {
import scala.collection.mutable.ListBuffer
def preorderTraversal(root: TreeNode): List[Int] = {
val res = ListBuffer[Int]()
def traversal(curNode: TreeNode): Unit = {
if(curNode == null) return
res.append(curNode.value)
traversal(curNode.left)
traversal(curNode.right)
}
traversal(root)
res.toList
}
}
```
中序遍历94. 二叉树的中序遍历)
```scala
object Solution {
import scala.collection.mutable.ListBuffer
def inorderTraversal(root: TreeNode): List[Int] = {
val res = ListBuffer[Int]()
def traversal(curNode: TreeNode): Unit = {
if(curNode == null) return
traversal(curNode.left)
res.append(curNode.value)
traversal(curNode.right)
}
traversal(root)
res.toList
}
}
```
后序遍历145. 二叉树的后序遍历)
```scala
object Solution {
import scala.collection.mutable.ListBuffer
def postorderTraversal(root: TreeNode): List[Int] = {
val res = ListBuffer[Int]()
def traversal(curNode: TreeNode): Unit = {
if (curNode == null) return
traversal(curNode.left)
traversal(curNode.right)
res.append(curNode.value)
}
traversal(root)
res.toList
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -413,8 +413,62 @@ func replaceSpace(_ s: String) -> String {
}
```
Scala:
方式一: 双指针
```scala
object Solution {
def replaceSpace(s: String): String = {
var count = 0
s.foreach(c => if (c == ' ') count += 1) // 统计空格的数量
val sOldSize = s.length // 旧数组字符串长度
val sNewSize = s.length + count * 2 // 新数组字符串长度
val res = new Array[Char](sNewSize) // 新数组
var index = sNewSize - 1 // 新数组索引
// 逆序遍历
for (i <- (0 until sOldSize).reverse) {
if (s(i) == ' ') {
res(index) = '0'
index -= 1
res(index) = '2'
index -= 1
res(index) = '%'
} else {
res(index) = s(i)
}
index -= 1
}
res.mkString
}
}
```
方式二: 使用一个集合,遇到空格就添加%20
```scala
object Solution {
import scala.collection.mutable.ListBuffer
def replaceSpace(s: String): String = {
val res: ListBuffer[Char] = ListBuffer[Char]()
for (i <- s.indices) {
if (s(i) == ' ') {
res += '%'
res += '2'
res += '0'
}else{
res += s(i)
}
}
res.mkString
}
}
```
方式三: 使用map
```scala
object Solution {
def replaceSpace(s: String): String = {
s.map(c => if(c == ' ') "%20" else c).mkString
}
}
```
-----------------------

View File

@ -291,6 +291,56 @@ func reverseString(_ s: inout [Character], startIndex: Int, endIndex: Int) {
```
### PHP
```php
function reverseLeftWords($s, $n) {
$this->reverse($s,0,$n-1); //反转区间为前n的子串
$this->reverse($s,$n,strlen($s)-1); //反转区间为n到末尾的子串
$this->reverse($s,0,strlen($s)-1); //反转整个字符串
return $s;
}
// 按指定进行翻转 【array、string都可】
function reverse(&$s, $start, $end) {
for ($i = $start, $j = $end; $i < $j; $i++, $j--) {
$tmp = $s[$i];
$s[$i] = $s[$j];
$s[$j] = $tmp;
}
}
```
Scala:
```scala
object Solution {
def reverseLeftWords(s: String, n: Int): String = {
var str = s.toCharArray // 转换为Array
// abcdefg => ba cdefg
reverseString(str, 0, n - 1)
// ba cdefg => ba gfedc
reverseString(str, n, str.length - 1)
// ba gfedc => cdefgab
reverseString(str, 0, str.length - 1)
// 最终返回return关键字可以省略
new String(str)
}
// 翻转字符串
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
}
}
}
```

View File

@ -380,50 +380,28 @@ func main() {
### javascript
```js
/**
*
* @param {Number []} weight
* @param {Number []} value
* @param {Number} size
* @returns
*/
function testWeightBagProblem (weight, value, size) {
// 定义 dp 数组
const len = weight.length,
dp = Array.from({length: len}).map(
() => Array(size + 1)) //JavaScript 数组是引用类型
for(let i = 0; i < len; i++) { //初始化最左一列即背包容量为0时的情况
dp[i][0] = 0;
}
for(let j = 1; j < size+1; j++) { //初始化第0行, 只有一件物品的情况
if(weight[0] <= j) {
dp = Array(len).fill().map(() => Array(size + 1).fill(0));
// 初始化
for(let j = weight[0]; j <= size; j++) {
dp[0][j] = value[0];
} else {
dp[0][j] = 0;
}
}
for(let i = 1; i < len; i++) { //dp[i][j]由其左上方元素推导得出
for(let j = 1; j < size+1; j++) {
// weight 数组的长度len 就是物品个数
for(let i = 1; i < len; i++) { // 遍历物品
for(let j = 0; j <= size; j++) { // 遍历背包容量
if(j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
return dp[len-1][size] //满足条件的最大值
}
console.table(dp)
function testWeightBagProblem2 (wight, value, size) {
const len = wight.length,
dp = Array(size + 1).fill(0);
for(let i = 1; i <= len; i++) {
for(let j = size; j >= wight[i - 1]; j--) {
dp[j] = Math.max(dp[j], value[i - 1] + dp[j - wight[i - 1]]);
return dp[len - 1][size];
}
}
return dp[size];
}
function test () {
console.log(testWeightBagProblem([1, 3, 4, 5], [15, 20, 30, 55], 6));

View File

@ -317,7 +317,55 @@ ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
}
```
Scala:
```scala
object Solution {
def getIntersectionNode(headA: ListNode, headB: ListNode): ListNode = {
var lenA = 0 // headA链表的长度
var lenB = 0 // headB链表的长度
var tmp = headA // 临时变量
// 统计headA的长度
while (tmp != null) {
lenA += 1;
tmp = tmp.next
}
// 统计headB的长度
tmp = headB // 临时变量赋值给headB
while (tmp != null) {
lenB += 1
tmp = tmp.next
}
// 因为传递过来的参数是不可变量,所以需要重新定义
var listA = headA
var listB = headB
// 两个链表的长度差
// 如果gap>0lenA>lenBheadA(listA)链表往前移动gap步
// 如果gap<0lenA<lenBheadB(listB)链表往前移动-gap步
var gap = lenA - lenB
if (gap > 0) {
// 因为不可以i-=1所以可以使用for
for (i <- 0 until gap) {
listA = listA.next // 链表headA(listA) 移动
}
} else {
gap = math.abs(gap) // 此刻gap为负值取绝对值
for (i <- 0 until gap) {
listB = listB.next
}
}
// 现在两个链表同时往前走,如果相等则返回
while (listA != null && listB != null) {
if (listA == listB) {
return listA
}
listA = listA.next
listB = listB.next
}
// 如果链表没有相交则返回nullreturn可以省略
null
}
}
```
-----------------------