• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2024-08-10 15:34 Aet 隐藏边栏 |   抢沙发  28 
文章评分 3 次,平均分 5.0

118 杨辉三角

Question

  1. 给定一个非负整数 numRows生成「杨辉三角」的前 numRows

Pic

Case

  1. 示例一:

  1. 实例二:

Tips

  1. 1 <= numRows <= 30

Ans1

  1. 初始版本

Ans2

  1. 优化版本

  1. 解析:
  2. if (numRows >= 1) {res.push_back({1});}
    1. 不管有一层还是多层,第一层都是一样的,都是{1}
  3. for (int i = 1; i < numRows; i++) {
    1. 这个循环,其实就是从第二层开始构建杨辉三角,numRows是多少,就需要构建多少层杨辉三角
    2. 而之所以从第二层(下标为1)的开始,是因为第一层通过if(numRows>=1){res.push_back({1});}这段代码已经构建好了
  4. vector<int> row(i+1, 1);
    1. 根据已知的规律(n层的杨辉三角,第11个元素,第22个元素,第n层有n个元素)来创建每一层用于存放杨辉三角的数据的容器的大小
    2. 并全部初始化为1(只所以这样做,是因为没一层的第一个和最后一个必然是1,这样全部初始化为1,只需要从每一层的第2个元素即下标为1的元素重新计算)
  5. for (int j = 1; j < i; j++) {
    1. 这个循环,对于每一层,从第2个元素开始重新计算它的值
      因为我们初始化的时候已经设置了正确的每一层的第一个以及最后一个元素
    2. 而第二个元素的下标为1,所以j从等于1开始
    3. j之所以需要小于i,对于每一层而言,下标的最大值就是i的值,所以当要用表示下标的j来处理元素,无论如何,j也不可以大于每一层的下标的最大值i
    4. 至于为什么不能等于下标i(最大值),因为最大值i表示了每一层的最后一个元素,而最后一个元素,我们在初始化的时候,已经赋予了它正确的值,所以不需要处理
  6. row[j] = res[i-1][j-1] + res[i-1][j];
    1. 因此,能执行这一行代码的情况,一定是在第一个元素和最后一个元素中间,还有元素的层
    2. 不满足这样的条件的层,不会执行这行代码,所以,对于{1,1}这样的情况(也就是第二层),自然无须担心

9 回文数

Question

  1. 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false
  2. 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数

Case

  1. 示例 1:

  1. 示例 2:

  1. 示例 3:

  1. 示例4:

Tips

Ans1

  1. 初始版本

Ans2

  1. 优化版本

  1. 解析
    1. 利用原数进行构建反转数,但只构建一半
    2. 构建循环的退出条件是构建的反转数等于或大于原数剩余的部分时,退出构建
    3. 然后进行判断,如果构建的反转数与原数的剩余部分相等,则是回文数
      不想等的情况,是构建的反转数比原数的剩余部分多一位
    4. 所以对构建的反转数进行一次以10取整,来判断是否相等,相等则为回文数,否则不是

13 罗马数字

Question

  1. 罗马数字包含以下七种字符: IVXLCDM

  1. 例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II27 写做 XXVII, 即为 XX + V + II

Case

  1. 示例1

  1. 示例2

  1. 示例3

  1. 示例4

  1. 示例5

Tips

  1. 通常情况下,罗马数字中小的数字在大的数字的右边
    1. 但也存在特例,例如 4 不写做 IIII,而是 IV
    2. 数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4
    3. 同样地,数字 9 表示为 IX
  2. 这个特殊的规则只适用于以下六种情况:
    1. I 可以放在 V (5) 和 X (10) 的左边,来表示 49
    2. X 可以放在 L (50) 和 C (100) 的左边,来表示 4090
    3. C 可以放在 D (500) 和 M (1000) 的左边,来表示 400900

Ans

14 最长公共前缀

Question

  1. 编写一个函数来查找字符串数组中的最长公共前缀
  2. 如果不存在公共前缀,返回空字符串 ""

Case

  1. 示例1

  1. 示例2

Tips

  1. 1 <= strs.length <= 200
  2. 0 <= strs[i].length <= 200
  3. strs[i] 仅由小写英文字母组成

Ans

58 最后一个单词的长度

Question

  1. 给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度
  2. 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串

Case

  1. 示例1

  1. 示例2

  1. 示例3

Ans1

Ans2

66 加一

Question

  1. 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一
  2. 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字
  3. 你可以假设除了整数 0 之外,这个整数不会以零开头

Case

  1. 示例1

  1. 示例2

  1. 示例3

Ans1

  1. 初始

Ans2

  1. 优化

67 二进制求和

Question

  1. 给你两个二进制字符串 ab ,以二进制字符串的形式返回它们的和

Case

  1. 示例1

  1. 示例2

Tips

  1. 1 <= a.length, b.length <= 104
  2. ab 仅由字符 '0''1' 组成
  3. 字符串如果不是 "0" ,就不含前导零

Ans

  1. 常规的思路不可行:
    1. bitsetab转成int(不是直接把streing转成int),再将相加后得到的int转成bitset,利用bitsetto_string得到二进制字符串
    2. 然后从左向右,使用stringfind找到第一个不为0的位,再使用substr从该位向后截取
    3. 对于常规的一些case来讲,该思路实现的方法是可以满足效果的
    4. 但是对于超级长的二进制字符串,bitsetto_ulong会截断处理,因此该方法不能正确处理大数
  2. 下面的方法是针对字符串进行处理

  1. 解析:
    1. int carry = 0;
    2. 用于存储每一位相加后的进位
    3. int i = a.size() - 1;
    4. int j = b.size() - 1;
    5. 从两个字符串的末位开始处理
    6. while (i >= 0 || j >= 0 || carry) {
    7. ij表示索引,那它当然要大于等于0,不管是长的字符串还是短的字符串,每一位都要处理
      同时carry保存的是进位,也需要处理
    8. int sum = carry;
    9. 临时的计算和
    10. if (i >= 0) {
    11. 由于ij在使用后会自减,所以循环中在使用前,需要对它进行判断,作为下标索引,它得大于等于0
    12. sum += a[i--] - '0';
    13. 首先是用字符减去字符0,利用ASCII编码的特点,将字符转成int
      然后把值保存到sum里面,同理,字符串b也需要进行同样的操作,都从最后一位开始
    14. res += (sum % 2) + '0';
    15. sum是两个字符串从末位对齐后,按末位相加的结果,之所以是%2,是因为事先知道目标元素是二进制10的字符相加所得到的结果,所以通过%2对相加结果进行取余,得到该位计算后最终的值
    16. 之后加上字符‘0’,是想把结果从int值转成ASCII字符
    17. carry=sum/2;
    18. 获得两同位字符按数字相加后在二进制规则下的进位量

125 验证回文串

Question

  1. 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个回文串
  2. 字母和数字都属于字母数字字符
  3. 给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false

Case

  1. 示例1

  1. 示例2

  1. 示例3

Tips

Ans1

Ans2

  1. 优化版

242 有效的字母异位词

Question

Case

Ans1

  1. map 是一个有序容器,插入和查找操作的时间复杂度为 O(log n)
    对于这个问题,使用无序容器 unordered_map 更合适,插入和查找的时间复杂度为 O(1),这将提高性能
  2. 代码中,先比较了 map 的大小,然后再逐一比较其中的元素
    这种情况下,可以在第二次遍历时直接查找和比较,而不需要额外的大小检查
  3. 因为字符范围已知(小写字母 a-z),可以直接使用一个大小为 26 的数组来统计每个字符的出现次数
    这会减少内存开销并提高查找效率

Ans2

  1. 优化

383 赎金信

Question

  1. 给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成
  2. 如果可以,返回 true ;否则返回 false
  3. magazine 中的每个字符只能在 ransomNote 中使用一次

Case

  1. 示例1

  1. 示例2

  1. 示例3

Ans

387 字符串中的第一个唯一字符

Question

  1. 给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1

Case

  1. 示例1

  1. 示例2

  1. 示例3

Tips

  1. 1 <= s.length <= 105
  2. s 只包含小写字母

Ans1

  1. 想法是用pos这个数组来记录所有字符第一次出现的索引
    1. pos初始化为-1,因为作为索引,是需要大于等于0
  2. 遍历字符串的每个字符,按照字符的ASCII值,在数组中下标为该值的位置记录下索引的值
    1. 记录的时候,如果该值为-1,表面第一次记录,于是更新成正确的索引值, 此时它是大于等于0
    2. 然后,对于再次循环时,该位置大于等于0的值再次处理,说明该外置的字符已经处理过了,是第二次次遇到了
    3. 于是把该外置的值更新为-2,表示该值是重复的,而后续对于第二次出现过的字符,已经不需要再处理了,跳过
  3. 这样,循环完,pos里面有3种值,-1-2,大于等于0
    1. 首先找打第一个大于等于0的,作为初始最小索引
    2. 然后遍历该数组,找到所有大于等于的索引里面最小索引
    3. 就是最早出现的唯一字符

Ans2

  1. 优化

389 找不同

Question

  1. 给定两个字符串 st ,它们只包含小写字母
  2. 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母
  3. 请找出在 t 中被添加的字母

Case

  1. 示例1

  1. 示例2

Tips

  1. 0 <= s.length <= 1000
  2. t.length == s.length + 1
  3. st 只包含小写字母

Ans1

Ans2

  1. 非优化,方案2

392 判断子序列

Question

  1. 给定字符串 st ,判断 s 是否为 t 的子序列
  2. 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串
    (例如,"ace""abcde"的一个子序列,而"aec"不是)
  3. 进阶:
    1. 如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列
      在这种情况下,你会怎样改变代码?

Case

  1. 示例1

  1. 示例2

Ans1

Ans2

  1. 另一种思路
    1. 先把t的每一个元素的所有索引用vector<vector<int>> vec_indexs保存下来
    2. 遍历s的每一个字符c,用cvec_indexs里面获取同字符的索引vector<int> vec
    3. 设置一个要查找的索引prev_index,初始化为-1,从vec里面查找有没有大于-1也就是prev_index的索引
    4. 查找使用二分查找auto ite = std::upper_bound(vec.begin(), vec.end(), prev_index);
    5. 如果找不到,那说明s的第一个字符在t里面都找不到,肯定不是t的子串,返回false
    6. 如果找到了,需要更新prev_index,而下一个字符的索引一定是要比前一个字符出现的最小索引要大的
    7. 所以把prev_index更新为*ite
    8. 循环到下一次时,要查的是下一个字符,而下一个字符的索引要大于prev_index
    9. 循环完成后,说明s的每一个字符都在t中按顺序找到了,返回true

415 字符串相加

Question

  1. 给定两个字符串形式的非负整数 num1num2 ,计算它们的和并同样以字符串形式返回
  2. 你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式

Case

  1. 示例1

  1. 示例2

  1. 示例3

Ans1

Ans2

  1. 针对上面的处理,当一个字符串长于另一个字符串时,去掉无进位的循环
    1. 比如1,1234599,当进位到第三位时,1234不需要再处理了,但上面的算法还是继续循环下去

Ans3

  1. 进阶,如果输入的字符串前面有负号,怎么处理

434 字符串中的单词数

Question

  1. 统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符
  2. 请注意,你可以假定字符串里不包括任何不可打印的字符

Case

  1. 示例1

Ans1

Ans2

Ans3

  1. ans1优化

459 重复的子串

Question

Case

Ans1

Ans2

Ans3

  1. 优化
    1. 如果一个字符串不是由子串组成的,那么把它拼接后,它就变成了由子串组成的了
    2. 此时,去掉首尾字符后,在剩余部分中必然找不到元串
    3. 同理,如果该字符串是由子串组成的,拼接后,取消首尾字符,必然能找到原串

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0 最后编辑于:2024-08-16
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享