LeetCode初级算法精选解答提示

LeetCode初级算法精选解答提示

easy

7.翻转整数

翻转的方法

  1. 转化为string后转为char[]
  2. 每次除10,并取余数,这样得出来的余数就是从个位数开始的

判断翻转的整数是否会越界的方法

  1. 先把值存储在Long中,最后再判断是否在Int的界限之外
  2. 直接try catch…该方法并不推荐
  3. 如果是上面的第二种翻转方法,可以在每次计算结果值之前,判断当前的结果值是否在边界值/10之外,或者与边界值/10相等但是当前的余数大于7(算是否比最大值还大时)、小于-8(算是否比最小值还小时)

8.字符串转整数 (atoi)

  1. 如果需要过滤开头的一部分空格字符,可以通过index值来记录起始位置,在代码开头单独循环判断一次。如" 46",先用一个循环得到第一个非空格位置,此处的index=1
  2. 判断正负值时也可以在上面的过滤空格循环之后,直接用if来判断,不需要再使用循环来判断。可以减少循环次数。
  3. char转换成int时,可以直接采用c - '0’的方式,或者Integer.parseInt(String.valueOf©)。注意Integer有两个方法,一个是valueOf(String s)返回的是Integer,另一个是parseInt(String s)返回的是基础类型int

13.罗马数字转整数

  1. 第一种方法,可以采用死方法,强行一个一个判断
  2. 第二种方法,与第一种类似,但是通过判断当前数是大于下一个数还是小于下一个数,从而来决定是减去这个数还是加上这个数

14.最长公共前缀

  1. 思路是使用第一个字符串与其它字符串轮流进行比较,如果不相等,就把第一个字符串的长度-1,直到相等位置才与之后的字符串进行比较

19. 删除链表的倒数第N个节点

  1. 只用一趟扫描实现查找倒数第N个节点的方法:声明两个值,先让一个值往右移动n次,再让两个值一起移动,最后当先移动的值到达末尾时,后移动的值就处在倒数n的位置上
  2. 删除一个节点有两个方法:①移动到要删除的节点,把该节点的值改成next.val,并指向next.next(相当于复制成它后面一个节点)②移动到要删除的节点的前一个位置,让其next=next.next(相当于直接把这个节点从链表中移出)

20.有效的括号

  1. 第一种方法,用Stack存储左括号,出现了右括号则取出第一个进行匹配
  2. 第二种方法:大神的方法,直接判断字符串中是否有()、[]、{},有的话则替换为""并一直循环,没有的话则跳出即可。最后判断字符串是否为空

21. 合并两个有序链表

  1. 需要生成新链表的题目,可以自己先声明一个链表头部,并用新变量存储这个链表头部,如ListNode(0),这样就不用再去每次判断新链表是否为null,最后返回新变量的next即可
  2. 在其中一个链表的情况,可以不用再循环里判断,把循环的条件改为(l1 != null && l2 != null),在循环结束之后肯定会出现了l1或者l2之中有一个为null的情况,再自己通过if语句加上即可。这样可以简化循环中的逻辑

28.实现strStr()

  1. 如果要在一个字符串中找到另一个字符串,最简单的方式就是使用haystack.indexOf(String s)
  2. 或者可以使用split(String s),这样分割的数组的第一位的长度就是s的起始位置
  3. 或者通过循环判断haystack.subString(i,i+lengthS)与所需字符串是否相等
  4. 直接通过i、j两个标记位置在循环中一同增长的方式
  5. indexOf的源码中,其实就是在循环中进行如下操作:从0开始进行一个lengthH-lengthS次数的循环A,在循环A中直接通过循环B找到首字符相同的位置,找到后循环B结束。通过循环C,以首字符、首字符+lengthH-1都相同的条件下进行循环,每次循环首字符都向后移动一位,直到移动了lengthH-1位后,即可判断匹配成功,返回首字符的位置即可。

38.报数

  1. 递归的方式,先写递归的出口。然后再调用自己即可

70.爬楼梯

无论哪种方法,都需要找到规律。

  1. 找规律:由于只有一步和两步的可能,所以n层的个数 = n-1层的个数+ n-2 层的个数
  2. 减少重复运算:由于n-1层又等于n-2层+n-3层,所以如果采取纯粹的递归的话会有大量的重复计算。所以采取空间换时间的方法,用一个数组来存储算出来的内容,因此可以直接从1开始按顺序计算到第n层,最后再返回n层的个数即可。

88. 合并两个有序数组

  1. 由于需要考虑到直接在循环的过程中插入时,会涉及到nums1需要一直往后移,所以可以考虑不要再从小开始遍历,应该从末尾的最大值开始遍历。
  2. 要灵活使用如nums1[m--]的用法,这样很节省代码量

98. 验证二叉搜索树

  1. 可以考虑先把所有值都按中序遍历的顺序提取到一个动态数组中。之后只要循环该动态数组即可判断是否满足二叉搜索树的需求。
  2. 中序遍历可以有两种方式进行遍历,第一种即递归,递归在几种顺序的遍历中都很方便,推荐使用;第二种即普通的循环,需要借助一个Stack来实现。先访问最左边的节点,途中的节点则存入该Stack,当读取到null时,才从Stack中读取最上层的数据,读取后再从右节点的子树开始判断。
  3. 最推荐的解法应该是用遍历的方式,并且把每个判断都放在遍历中做,这样可以节省空间。

101. 对称二叉树

1.递归解法:在递归解法时,一定要明确该函数的功能是什么。如此题,目的就是判断左子树和右子树是否是镜像的。
2.遍历解法:使用层级遍历,由于镜像是相反的,所以左子树和右子树的节点采取相反的方向插入即可,如左子树先插入left,再插入right;而右子树则相反。这样即可判断是否是对称二叉树。

102. 二叉树的层次遍历

  1. 在对队列进行循环遍历时,最好还是把size先取出来,以防在循环时取出或者插入值导致size被改变。
  2. ArrayList使用clear与重新new一个的情况需要分清,特别是在List<ArrayList>中的情况。
  3. 如果使用遍历的方法来进行层次遍历,则需要在遍历的时候新增一个length,用来表示当前是第几层。

104.二叉树的最大深度

  1. 采取递归的方式来获取左右子节点,当其本身为空,则返回此子树高度为0
  2. 采取每次都放同样深度的节点放到队列里,然后再循环取出,再放入下一层,这样每一层就使可以长度加一

108. 将有序数组转换为二叉搜索树

  1. 在进行递归时,一定要先弄清楚除了循环之外的特殊情况。如此问题,需要搞清楚当start==end与start>end时需要返回的情况。

118.杨辉三角

  1. 第一种方法,直接通过ArrayList和两层循环的方式
  2. 第二种方法,双层循环+二维数组,二维数组由于是正方形,所以判断每一行的第一项和最后一项就很方便了,分别是k = 0和k = i

121. 买卖股票的最佳时机

  1. 主要是需要找到波峰与波谷。
  2. 需要存储两个值即最小值和结果值。若发现了更小的,则直接替换最小值。(因为如果发现了最小值,之后的峰值则与前面的最小值无关了,所以不需要再保存)。而如果不是更小的,则直接计算与最小值的差值,来判断是否需要替换结果值。

125.验证回文串

判断大小写字母

  1. 可以使用String的api:toLowerCase直接把所有的字符转化为小写后比较。
  2. 直接根据它们减去’a’与’A’的差值判断是否在正确范围内,如果在正确范围内就存储这个差值。(由于字母差值会与数字冲突,所以可以采取字母的所有差值+10的策略)

节省空间的方法

在一些方法需要过滤掉一些无用的字符时,我们可以使用已经比较过的位置进行保存,从而节省空间。如"a bcd",我们过滤无用信息后,可以变成"abcdd",并通过一个int值记录有效位置。这样的好处就是不用再重新声明一个char数组来存储过滤后的信息,从而实现空间的重复利用

141.环形链表

采取双指针的方法来判断是否为环形链表

155.最小栈

  1. 就是在栈的基础上多出了一个查询最小值的功能,所以可以通过加一个栈用于存储当前最小值
  2. 在pop时,需要判断当前取出的值是不是最小值,如果是则需要同步在最小值的栈中取出
  3. 不过要注意的是在pop时,如果使用Stack的peek方法,取出的不是int值,而是一个Object的对象,因此不能直接用==来进行比较两个栈通过peek方法取出来的值。
  4. 注意!!!如果连续输入0,1,0,当调用了pop之后,需要保证minStack里仍然有一个0存在,所以就算是当前值和最小值重复,也必须放入最小值栈中,即出现0,0的情况
  5. 还有一种只用一个栈实现的方法,即把最大值直接放到栈的最后,如:入栈序列为2-3-1,则入栈后栈中元素序列为:2-2-3-2-1-1 ,这样的话pop就相当于连续对stack调用两次pop

189.旋转数组

  1. 推荐采取三次旋转(有关数组的旋转都可以采取此种方式)
  2. https://blog.csdn.net/biezhihua/article/details/79535021

190. 颠倒二进制位

  1. 做这类二进制操作的题目更轻松的还是采用位运算的方式。通过>>和&1来轮流得到n对应位置的值是0还是1。
  2. 之后新声明一个数a,来通过<<轮流存储n中得到的值。
  3. 注意左移或者右移的次数,不要对结果造成影响。

191.位1的个数

  1. 第一种方法是通过轮询进行&1操作来判断
  2. 第二种方法则是通过位来进行计算,首先通过每两位来表示这两位1的个数,然后通过每四位来表示这四位1的个数,然后是八位、十六位,最后是三十二位即可。记得把无效位给去掉
  3. 第二种方法网址:https://blog.csdn.net/u011497638/article/details/77947324

198.打家劫舍

  1. 这种问题都可以采取动态规划的方法,让问题变得相当直观。动态规划赛高!

204.计数质数

  1. 这种问题就采用厄拉多塞筛法,用空间换时间,新建一个结果数组,存储表示每个数的结果,并直接从2开始,从结果数组中划掉他们的倍数(即不是质数)
  2. 优化点:在划倍数的这层循环中,不需要从2倍开始,而是从i*i倍开始,因为2倍从2*2开始就已经计算过了。同理,只需要从i*i计算到sqrt(n)。

206.翻转链表

  1. 迭代的方式:由于从头开始翻转会导致无法找到下一个或者上一个节点,所以需要用三个值在翻转前,分别记录前一个node、当前node、下一个node
  2. 递归的方式:递归的目的是为了从最后一个节点开始。递归的好处是修改了next或者next.next之后,当前的head总是我们所需要翻转的目标位置。

234.回文链表

  1. 找到链表中点的方式,声明fast与slow都指向head,每循环一次fast移动两次,slow移动一次,这样当fast移动到队尾或者队尾之后时,slow正好处在链表中心的位置。
  2. 若要判断回文链表,可以翻转链表的后半段。并比较前半段和后半段是否相等即可。

242.有效的字母异位词

  1. 对字母进行计数时,可以通过采取空间换时间的策略。即声明一个size=26的int数组,每个位置的int大小表示该字母出现的次数
  2. Arrays.sort方法可以快速对数组进行排序,在工作中可以常用

268.缺失数字

  1. 极限情况会越界的方法:通过算出0~n的累加值,即n(n+1)/2,再减去数组的总和,即可得到缺少的值。
  2. 更好的大神方法:通过异或来进行判断,因为44=0,0^4=4。通过这种特性让数组轮流与1~n在同一个值上进行异或,最后得到的值就是缺少的那个值。

278.第一个错误的版本

简单来说就是使用二分法进行查找即可,注意最终返回的取值如果不确定,可以模拟一个情景。

326.3的幂

  1. 最简单的方法,是用整数范围内的数对n进行整除,但是这样还得运算整数范围内最大的3的幂
  2. 第二种方法,若是3的幂,则一定是在3进制下类似10000的这种数,所以把n通过Integer.toString(n,3)转换成string,再对string进行判断即可
  3. 第三种方法,通过递归或者循环进行判断,相对最容易想到

387.打乱数组

  1. 数组直接赋值给另一个数组,则两个数组之后仍然会相互影响!要解决相互影响的问题,采用nums1 = Arrays.copyOf(nums2,nums2.length);
  2. 此处采用的是洗牌算法,与之前自己写的抽签系统类似,但是要注意如果从0开始交换,交换的位置需要缕清楚。比如i=0,交换0length-1的随机数。当i=2时,交换1length-1的随机数,而不是0~length-2的随机数。

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

  1. 查找字符相关的问题,除了从第一个开始循环之外,还可以通过循环字母表来实现
  2. 判断是否是重复的字符,还可以判断String的indexOf与lastIndexOf是否相等来实现

1012.十进制整数的反码

  1. 难点在于如何判断是否需要在最高的有效位取反,如0x00001010,有效位只是1010而已。
  2. 有两种方法判断有效位个数。①通过循环往右移动该数,且记录移动次数,当值为0时,表示所有位数已经移动完毕了。②把一个数从1开始往左移,不要大于该数,左移的次数即为有效位数。

1014.在D天内运送包裹的能力

  1. 首先需要知道可能的最大值与最小值,最小值肯定就是最大的那个货物的重量,最大值是所有货物的总重量(就是一条船一天直接全部装走)
  2. 开始使用二分法求出刚好的值,如果当前的载重量使用的天数大于规定的天数,就表示当前的载重量不足,所求值在右半边。相反则就是在左半边

猜你喜欢

转载自blog.csdn.net/wangzici/article/details/89099377
今日推荐