前端刷题路-Day1

1,681 阅读3分钟

两数之和(题号1)

题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

你可以按任意顺序返回答案。

示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

提示:
2 <= nums.length <= 103
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案

链接

leetcode-cn.com/problems/tw…

解释

要开始研究算法,LeetCode必不可少。

要刷LeetCode,自然要从第一题开始。

这题是简单题,如果想到那种方法就很简单了,想不到的话可能就是想不到了。

想找到两个和为target的数,可以换个思路,先找到target和一个数的差,如果后续循环的时候,有某一个数字在这一堆差里头,那么找到这个差的index和当前的index即可。

而且注意题目的描述:

只会存在一个有效答案

那就是不存在没有答案的情况,特殊情况也不用考虑了,十分简单。

自己的答案(数组)

var twoSum = function(nums, target) {
  var arr = []
  for (let i = 0; i < nums.length; i++) {
    var res = arr.findIndex(item => item === nums[i])
    if (res > -1) return [res, i]
    arr[i] = target - nums[i]    
  }
};

这里是利用的数组的findIndex()方法,因为对具体的值不敏感,只关心它的index

自己的答案(Map

Map的话性能会好一些,毕竟它的读写比数组快,而且不需要写判断条件。

var twoSum = function(nums, target) {
  var group = new Map()
  for (let i = 0; i < nums.length; i++) {
    if (group.has(nums[i])) return [group.get(nums[i]), i]
    group.set(target - nums[i], i)
  }
};

答案就是这样,很清晰易懂

这题主要考的是哈希表,第一步存储差到数组或者Map中就是一个哈希表,之后在表里查找正确答案就行了,笔者看了看其他的一些答案,JavaScript基本上都是这个解法,如果更好的方法欢迎在评论区指出

更好的方法

整数反转(题号7)

题目

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:
输入:x = 123
输出:321

示例 2:
输入:x = -123
输出:-321

示例 3:
输入:x = 120
输出:21

示例 4:
输入:x = 0
输出:0

提示:
-231 <= x <= 231 - 1

链接

leetcode-cn.com/problems/re…

解释

看到这题的第一眼就已经想好了做法,的确,这种方法的确是可行的,但其实还有另外一种方法。

自己的答案(经典数组)

var reverse = function(x) {
  var num = +Math.abs(x).toString().split('').reverse().join('')
  if (num > Math.pow(2, 31) - 1 || num < Math.pow(-2, 31)) return 0
  return x < 0 ? 0 - +num : +num
};

说实话,性能并不比另外一种差,可以说是不相伯仲。

执行用时:88 ms, 在所有 JavaScript 提交中击败了96.37%的用户

内存消耗:39 MB, 在所有 JavaScript 提交中击败了96.66%的用户

更好的方法(位运算)

var reverse = function(x) {
  var res = 0
  while (x) {
    // res每次增加10倍,然后加上新增的数据
    res = res * 10 + x % 10
    if (Math.abs(res) > Math.pow(2, 31)) return 0
    // 一个~是按位取反,两个~~是直接去掉小数点后面的内容
    // 而且~~不会改变数字的正负,这一点比Math.floor()强不少
    x = ~~(x/10)
  }
  return res
};

其实就是10位10位的累加,又点类似于有经典是10位进1的操作,但又有些许不同。

这样对x一次次对遍历,最终x会被拆解为0,拆解完成时还没越界就直接返回res

回文数(题号9)

题目

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。

示例 1: 输入:x = 121
输出:true

示例 2:
输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3: 输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

示例 4:
输入:x = -101 输出:false

提示:

-231 <= x <= 231 - 1

进阶:你能不将整数转为字符串来解决这个问题吗?

链接

leetcode-cn.com/problems/pa…

解释

其实和上面的整数反转的代码差不多,就是可以通过一些判断直接过滤掉一些结果。

比方说负数必然不会时回文数,还有就是可以被10整除的数,因为被10整除的数最后一位必然是0,但没有数字是以0开头的。

自己的答案(位运算)

var isPalindrome = function(x) {
  if (x < 0 || (x > 0 && x % 10 === 0)) return false
  var xBefore = x
      xEnd = 0
  while (x) {
    xEnd = xEnd * 10 + x % 10
    x = ~~(x / 10)
  }
  return xBefore === xEnd
};

跑得也还不错,抽风的时候可以跑到下面这个成绩,感觉LeetCode是用时和内存消耗很不稳定,没谱的事。

执行用时:196 ms, 在所有 JavaScript 提交中击败了92.80%的用户

内存消耗:46.2 MB, 在所有 JavaScript 提交中击败了97.63%的用户

更好的方法(数学算法)

这块就有点超纲了,感觉这辈子都写不出这样的代码,贴一下地址吧:

leetcode-cn.com/problems/pa…



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)

有兴趣的也可以看看我的个人主页👇

Here is RZ