从零开始的力扣刷题记录-第八十七天

129. 求根节点到叶节点数字之和-中等

题目描述:
给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:
例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。
叶节点 是指没有子节点的节点。

题解:
简单的深度优先搜索就可以解决

代码(Go):

func sumNumbers(root *TreeNode) int {
    return dfs(root,0)
}

func dfs(root *TreeNode,sum int) int {
    if root == nil {
        return sum
    }
    sum = sum * 10 + root.Val
    NewSum := 0
    if root.Left == nil && root.Right == nil{
        return sum
    }
    if root.Left != nil{
        NewSum += dfs(root.Left,sum)
    }
    if root.Right != nil{
        NewSum += dfs(root.Right,sum)
    }
    return NewSum
}

130. 被围绕的区域-中等

题目描述:
给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。

题解:
没有被包围的O一定与边界上的O相连,所以可以反过来从边界上的O开始找到所有相连的O并标记,最后遍历矩阵,被标记的O变回O,没有被标记的O改为X

代码(Go):

func solve(board [][]byte)  {
    for i := 0;i < len(board);i++{
        for j := 0;j < len(board[0]);j++{
            if (i == 0 || j == 0 || i == len(board) - 1 || j == len(board[0]) - 1) && board[i][j] == 'O'{
                checkout(board,i,j)
                board[i][j] = '1'
            }
        }
    }
    for i := 0;i < len(board);i++{
        for j := 0;j < len(board[0]);j++{
            if board[i][j] == '1'{
                board[i][j] = 'O'
            }else{
                board[i][j] = 'X'
            }
        }
    }
    return
}

func checkout(board [][]byte,x int,y int) {
    if x - 1 >= 0 && board[x - 1][y] == 'O'{
        board[x - 1][y] = '1'
        checkout(board,x - 1,y)
    }
    if y - 1 >= 0 &&board[x][y - 1] == 'O'{
        board[x][y - 1] = '1'
        checkout(board,x,y - 1)
    }
    if x + 1 < len(board) && board[x + 1][y] == 'O'{
        board[x + 1][y] = '1'
        checkout(board,x + 1,y)
    }
    if y + 1 < len(board[0]) && board[x][y + 1] == 'O'{
        board[x][y + 1] = '1'
        checkout(board,x,y + 1)
    }
    return
}

437. 路径总和 III-中等

题目描述:
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

题解:
代码写麻烦了,官方题解更容易懂。我的思路是用一个flag变量标记此节点是否必选,如果此节点的父节点已经被选中到路径中则该节点必须被选择,然后就是常规的深度优先搜索统计即可

代码(Go):

func pathSum(root *TreeNode, targetSum int) int {
    return search(root,targetSum,0)
}

func search(root *TreeNode,targetSum int,flag int) int {
    if root == nil{
        return 0
    }
    if root.Val == targetSum && flag == 0{
        return 1 + search(root.Left,0,1) + search(root.Right,0,1) + search(root.Left,targetSum,0) + search(root.Right,targetSum,0)
    }else if root.Val == targetSum && flag == 1{
        return 1 + search(root.Left,0,1) + search(root.Right,0,1)
    }else if flag == 0{
        return search(root.Left,targetSum,0) + search(root.Right,targetSum,0) + search(root.Left,targetSum - root.Val,1) + search(root.Right,targetSum - root.Val,1)
    }else{
        return search(root.Left,targetSum - root.Val,1) + search(root.Right,targetSum - root.Val,1)
    }
}

376. 摆动序列-中等

题目描述:
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

题解:
子序列问题直接想到动态规划,整体思路和最长递增子序列问题基本一致,但是因为每次判断dp[i]时都需要和前面所有的位置依次对比,所以时间复杂度是O(n²),官方题解使用了两个dp数组分别表示最后一个元素是上升状态的上升数组和最后一个元素是下降状态的下降数组,两个数组的第n个状态都可以通过两个数组的n-1个状态共同得出,这样既使时间复杂度降到了O(n),也使空间复杂度降到了O(1),具体可以看下官方题解

代码(Go):

func wiggleMaxLength(nums []int) int {
    dp := make([]int,len(nums))
    sign := make([]int,len(nums))
    for i := 0;i < len(nums);i++{
        if i == 0{
            dp[i] = 1
            sign[i] = 0
        }else if i == 1{
            if nums[i] > nums[0]{
                sign[i] = 1
                dp[i] = 2
            }else if nums[i] < nums[0]{
                sign[i] = -1
                dp[i] = 2
            }else{
                sign[i] = 0
                dp[i] = 1
            }
        }else{
            max := 0
            for j := 0;j < i;j++{
                if sign[j] == 1 && nums[i] < nums[j]{
                    if dp[j] + 1 > max{
                        max = dp[j] + 1
                        sign[i] = -1
                    }
                }else if sign[j] == -1 && nums[i] > nums[j]{
                    if dp[j] + 1 > max{
                        max = dp[j] + 1
                        sign[i] = 1
                    }
                }else if sign[j] == 0{
                    if dp[j] + 1 > max && nums[i] > nums[j]{
                        max = dp[j] + 1
                        sign[i] = 1
                    }else if dp[j] + 1 > max && nums[i] < nums[j]{
                        max = dp[j] + 1
                        sign[i] = -1
                    }
                }
            }
            dp[i] = max
        }
    }
    max := 0
    for i := 0;i < len(nums);i++{
        if dp[i] > max{
            max = dp[i]
        }
    }
    return max
}

总结

终于忙完了一个大阶段,正式回归!但是因为现在还要上课而且两道简单两道中等现在变成了四道中等,所以不一定能保证每天全靠自己做完四道题了,只能说尽量完成,如果时间不够的话就只能把没解出来看了题解的题也搬上来了

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于力扣刷C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷中,使用 string 可以方便地处理字符串相关的问。 9. 注意边界条件:在力扣刷中,边界条件往往是解决问的关键。需要仔细分析目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值