LeetCode新手村题目分析

题目

1480 一堆数组的动态和

给你一个数组 nums 。数组「动态和」为:runningSum[i] = sum(nums[0]…nums[i]) 。请返回 nums 的动态和
分析:
每一个 sum[i] 都是前一个 sum[i] 与 nums[i] 之和
即循环遍历nums,nums[i] += nums[i-1]。

383 赎金信(字符构成)

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
分析:
用 int rec[26] 来记录字符出现次数,遍历magazine,加一记录组件字符,再遍历ransomNote,减一记录要组成的字符,同时判断其值,小于0则不能构成。

412 Fizz Buzz(判断)

给你一个整数 n ,找出从 1 到 n 各个整数的 Fizz Buzz 表示,并用字符串数组 answer(下标从 1 开始)返回结果,其中:
answer[i] == “FizzBuzz” 如果 i 同时是 3 和 5 的倍数。
answer[i] == “Fizz” 如果 i 是 3 的倍数。
answer[i] == “Buzz” 如果 i 是 5 的倍数。
answer[i] == i (以字符串形式)如果上述条件全不满足。
分析:
if 嵌套外3内5,都满足则FB,内else满足3则F,外else if 满足5则B,外else 都不满足则to_string(i);
字符串数组末尾加值可用answer.emplace_back(“Buzz”)。

876 链表的中间结点(快慢指针)

给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
分析:
快指针p走两步,慢指针q走一步,快指针p走到末尾时,慢指针q刚好走到中间。
while(!p)遍历链表,i++计数,i%2 =0时(p->next两次),q->next一次。遍历结束,返回q恰好在中间。

1342 将数字变成0的操作次数

给你一个非负整数 num ,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。
分析:
while(num) 中进行除2或减1操作,记录总操作次数。

1672 最富有客户的资产总量

给你一个 m x n 的整数网格 accounts ,其中 accounts[i][j] 是第 i​​​​​​​​​​​​ 位客户在第 j 家银行托管的资产数量。返回最富有客户所拥有的 资产总量 。最富有客户就是 资产总量 最大的客户。
客户的 资产总量 就是他们在各家银行托管的资产数量之和。
分析:
temp记录每个客户的总资产,max = max > temp?max:temp;

2236 判断根结点是否等于子结点之和

给你一个 二叉树 的根结点 root,该二叉树由恰好 3 个结点组成:根结点、左子结点和右子结点。
如果根结点值等于两个子结点值之和,返回 true ,否则返回 false 。
分析:
判断 根->val == 根->左->val + 根->右->val。

26 删除有序数组中的重复项

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
分析:
先判空,空返回k为0;
以下标代指针,快慢指针 i = j = 1,默认已存放nums[0]。
相邻两数比较( i与i-1),不等则慢指针 j 存放 i 值(后一个数),再j++。相等则 j 不动。遍历结束返回 j 。

21 合并两个有序列表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。
分析:
迭代法,先定义指针list3与p指向新链表头结点(有/无值都可)。p用于不断新增结点。
两链表都非空时,比较大小链接值小的结点。
list1->val < list2->val时 ,list3头结点的next(p->next)链接较小的 list1结点 ,再将list1与p向后移动(p = p->next后p指向刚刚加入的list1结点),反之亦然。
跳出循环时仅有一链表非空,再链接该非空链表即可。
p->next = list1 == NULL ? list2 : list1;
最后返回list3->next(除头结点外的有值部分)。

215 数组中的第K个最大元素(快排+减治)

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。时间复杂度须为 O(n) 。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
分析:
快排+减治partition:分而治之的同时仅处理一个分支。
升序快排,求第K大的元素,则其下标为len-k。
快排主体:减治+递归调用快排函数。
减治:pivot选最后一个元素,遍历数组,小于等于pivot则放在前面。循环结束后,把pivot放在小数区的后一位,并返回此时下标。如果pivot选第一个元素,则大于pivot时放在后面,循环结束后pivot放在大数区前一位。
递归结束条件是pivot下标为len-k,否则缩小数组区间,继续调用快排函数。

221 最大正方形(动态规划)

在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。
分析:
动态规划要从中间值考虑问题,即如何通过前值得到该中间值。
用 dp[i][j] 存储以矩阵 (i, j) 为右下角的正方形 的最大边长。
矩阵 (i, j) 为0时, dp[i][j] = 0。为1时,dp[i][j] 的值由其左,上,左上方的dp值决定,即三者dp最小值加1。
矩阵 (i, j) 为1时,还需考虑边界情况(即 i / j 为0时),其dp值为1。
循环内计算maxdp = max(maxdp, dp[i][j]),循环外算面积返回即可。

5 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。
分析:
动态规划法
子串长度为1,必然为回文。
用 dp[i][j] 记录子串(i~j)是否为回文子串,初始默认都为回文即1。
如果s[i] != s[j],则该子串不是回文子串,dp[i][j] = 0;
如果s[i] == s[j],则该子串是否为回文子串,由其内部子串决定。
dp[i][j] = dp[i+1][j-1];内部子串是回文且两头相等,则该子串也为回文。
返回子串substr需知起始下标和子串长度。于是我们枚举子串长度和起始下标,把结束下标用起始下标和长度表示。
当 确定为回文子串 且 子串长度更大 时,循环中不断更新起始位置和子串长度。
最后用s.substr(begin,maxlen)输出该子串。

中心扩散法
动态规划中状态转移方程如下3个,

  1. p(i,i) = true;
  2. p(i,i+1) = (s[i]= s[i+1]) ;
  3. p(i,j) = p(i+1,j-1) & (s[i]= s[j]);

即我们可推出p(i,j) <- p(i+1,j-1) <- p(i+2,j-2) <- …(边界情况)。
其中前两个方程为边界情况,即回文中心。我们可以从回文中心开始推导拓展,直到无法拓展。
两者的拓展过程相同,可提取为函数,其内容为循环下 满足条件时 i 和 j 进行变化。最后返回pair对象,即含两个数据的结构体。eg:pair<int, int> p1;
主函数 在循环中 根据拓展函数返回的 i 和 j 判断子串长度是否更长并更新。
最后仍用s.substr(begin,maxlen)输出该子串。

79 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
分析:
使用深度优先算法和回溯进行搜索。
注意回溯应用visited[i][j]数组标记各网格是否已被访问
外层遍历每个网格,对其进行深度优先搜索(进入递归函数)。
内层递归,先判断该网格是否为word[k],是则标记为已访问,进而访问其4个方向(用pair数组保存),使用时注意方向是否越界。
未曾访问该方向的网格 则进行递归,注意递归函数返回为false时仅为该方向失败,还需递归其他方向。
4个方向都失败,则应回溯 后退到初始网格,注意需将标记访问数组还原为未访问,再重新搜索。

518 零钱兑换 ||

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带符号整数。
分析:
通过动态规划计算可能的组合数,用dp[i]表示金额之和等于i的硬币组合数
动态规划的边界为 dp[0] = 1,即仅一种即不选任何硬币时金额为0。
外层循环是遍历数组 coins 的值,内层循环是遍历不同的金额之和 i 。
遍历 i 从 coin 到 amount ,dp[i] += dp[i - coin]。

103 二叉树的锯齿形层序遍历

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
分析:
广度优先遍历,用队列queue维护当前层的节点。该层非空(外循环)时,求出队列长度,再对其中每个节点进行遍历(内循环)。
用双端队列deque(两端都可入队)维护该层遍历后的 值,同时维护一个isOrderLeft变量 标记该层的遍历顺序,选择值的入队方向。同时记录其子节点到queue中。
每层遍历结束,对isOrderLeft取反,并将双端队列的值插入结果二维数组中。

204 计数质数

给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。
分析:
暴力枚举并计数,简单但时间复杂度较高。
判断是否为质数,在 i * i <= num 时,用 num % i == 0 判断,num为0~n-1 。
埃氏筛
如果 x 是质数,那么大于 x 的 x 的倍数 2x,3x,… 一定不是质数。
用isPrime[i] 表示数 i 是不是质数,初始都为1。从 i * i 开始标记为0,因为2i,3i 等一定已被其他数的倍数所标记,并继续标记 (i+1)*i,(i+2)i 等。
注意 从 i
i 开始的 各个倍数的大小 不能越界。

问题

递归和迭代

递归:一个函数调用自身。
需满足条件:一是子问题和初始问题相同;二是保证有限地调用,可化简为非递归状况处理。
迭代:在循环中利用已知变量值,根据递推公式不断得到变量新值。
与普通循环的区别:参与运算的变量同时也是保存结果的变量,保存的结果将作为下一次运算的初值。

动态规划

动态规划是利用历史数据来避免重复计算,一般用一维或二维数组dp来存储这些历史数据。
步骤

  1. 定义数组元素的含义。
  2. 找出数组元素之间的关系,列出状态方程。
  3. 找初始值,确定边界情况。

回溯

用深度优先算法搜索解空间,当一条路走到尽头时,后退若干步从另一条路进行搜索。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值