(立下flag)每日10道前端面试题-08 十道算法简单算法

1.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。若是目标值不存在于数组中,返回它将会被按顺序插入的位置。git

你能够假设数组中无重复元素。数组

示例 1:

输入: [1,3,5,6], 5
输出: 2
示例 2:函数

输入: [1,3,5,6], 2
输出: 1
示例 3:编码

输入: [1,3,5,6], 7
输出: 4
示例 4:spa

输入: [1,3,5,6], 0
输出: 0prototype

解一:3d

仍是indexOf开头,若是存在返回索引值,不然就push一下给它生米煮成熟饭,再排序,从新返回索引值。指针

image.png
解二:code

老实方法用for遍历,存在(=)和不存在(>)两种状况能够一块儿处理。blog

image.png
解三:

使用二分法,也是这道题真正想考察的方法。

二分法理解起来很简单,小学就学过。可是实际编码时,边界防范、左右中位数的取舍、while中的条件以及是否+1何处+1能够说是要到处设防。

image.png

2.. 外观数列

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项以下:

  1. 1
  2. 11
  3. 21
  4. 1211
  5. 111221

1 被读做  "one 1"  ("一个一") , 即 11。
11 被读做 "two 1s" ("两个一"), 即 21。
21 被读做 "one 2",  "one 1" ("一个二" ,  "一个一") , 即 1211。

给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。

注意:整数序列中的每一项将表示为一个字符串。

 

示例 1:

输入: 1
输出: "1"
解释:这是一个基本样例。
示例 2:

输入: 4
输出: "1211"
解释:当 n = 3 时,序列是 "21",其中咱们有 "2" 和 "1" 两组,"2" 能够读做 "12",也就是出现频次 = 1 而 值 = 2;相似 "1" 能够读做 "11"。因此答案是 "12" 和 "11" 组合在一块儿,也就是 "1211"。

解一:
经过正则合并相同元素完成累加
image.png

解二:

这种类型的题目用字典不是特别爽吗?

image.png

3. 最大子序和

给定一个整数数组 nums ,找到一个具备最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:

若是你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

解题思路:
示例: [a, b , c, d , e]

解答这类题目, 省略不掉遍历, 所以咱们先从遍历方式提及

一般咱们遍历子串或者子序列有三种遍历方式

以某个节点为开头的全部子序列: 如 [a],[a, b],[ a, b, c] ... 再从以 b 为开头的子序列开始遍历 [b] [b, c]。
根据子序列的长度为标杆,如先遍历出子序列长度为 1 的子序列,在遍历出长度为 2 的 等等。
以子序列的结束节点为基准,先遍历出以某个节点为结束的全部子序列,由于每一个节点均可能会是子序列的结束节点,所以要遍历下整个序列,如: 以 b 为结束点的全部子序列: [a , b] [b] 以 c 为结束点的全部子序列: [a, b, c] [b, c] [ c ]。
第一种遍历方式一般用于暴力解法, 第二种遍历方式 leetcode (5. 最长回文子串 ) 中的解法就用到了。

第三种遍历方式 由于能够产生递推关系, 采用动态规划时, 常常经过此种遍历方式, 如 背包问题, 最大公共子串 , 这里的动态规划解法也是以 先遍历出 以某个节点为结束节点的全部子序列 的思路

对于刚接触动态规划的, 我感受熟悉第三种遍历方式是须要抓住的核心

由于咱们一般的惯性思惟是以子序列的开头为基准,先遍历出以 a 为开头的全部子序列,再遍历出以 b 为开头的...可是动态规划为了找到不一样子序列之间的递推关系,偏偏是以子序列的结束点为基准的,这点开阔了咱们的思路。

我在网上看很多解答时,直接阅读其代码,老是感受很理解很吃力,由于好多没有写清楚,一些遍历到底表明什么意思,看了许久仍不知因此然,下面的代码中摘录了 维基中的解释,感受比较清楚,供你们理解参考。

代码:
image.png
image.png

第二块代码和 第一块代码 思路实现是彻底同样的,可是若是第一次看到这类题目,直接阅读 第二块代码,理解起来很难,尤为是 若是改为 if (sum > 0 ) 对于刚接触的这题目的比较很差理解。

4. 最后一个单词的长度

给定一个仅包含大小写字母和空格 ' ' 的字符串 s,返回其最后一个单词的长度。若是字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。

若是不存在最后一个单词,请返回 0 。

说明:一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。

 

示例:

输入: "Hello World"
输出: 5

解一:使用trim
image.png

解法二:遍历
从右往左最后一个字符位置开始,求最后一个单词的开头和结尾字符索引位置,相减即为所求
结尾字符记录索引为end,初始化为字符串结尾字符索引
遇到空字符,end--
不然
end < 0,越界,字符串为空或不存在,返回0
end > 0
继续end--判断字符串是否为空
不为空,则说明找到了最后一个单词的结尾字符索引位置
开头字符初始化为 start = end,依旧向前遍历
不为空,则 end--
为空,则说明找到了最后一个单词的首字符位置 start
结果
end - start

image.png

5. 加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每一个元素只存储单个数字。

你能够假设除了整数 0 以外,这个整数不会以零开头。

示例 1:

输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。

示例 2:

输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321。

解法一:使用es10 bigint

  • 已知传入参数一定为数值型数组
  • 将参数转换为字符型(Array.prototype.join())
  • 由字符型变为BigInt型(BigInt构造函数))
  • 进行专属于BigInt类型的数学计算
  • 计算结果再次变为字符型(String构造函数)
  • 将字符型数值变动为数组(String.prototype.split())

如下是相应的代码实现:

image.png

方法二: 小学生加法
咱们将问题简化为第i位(0 <= i < n)加一或加0。
而加一的结果分为两种状况:

加一后须要进位
加一后不须要进位
对于第二种状况,咱们直接返回digits就能够。
对于第一种状况,咱们将指针移到前面一位。继续一样处理。
而边界状况即,首位也产生进位,首位产生进位只会是999....9999这种状况,咱们也很容易得出结果。

image.png

6. 二进制求和

给你两个二进制字符串,返回它们的和(用二进制表示)。

输入为 非空 字符串且只包含数字 1 和 0。

 

示例 1:

输入: a = "11", b = "1"
输出: "100"
示例 2:

输入: a = "1010", b = "1011"
输出: "10101"
 

提示:

每一个字符串仅由字符 '0' 或 '1' 组成。
1 <= a.length, b.length <= 10^4
字符串若是不是 "0" ,就都不含前导零。

解法一:利用BigInt解决溢出的问题

image.png

解法二:小学生加法

  • 先对两个字符串按照最长长度,在前面用'0'补全长度
  • 而后对字符串从后向前遍历,对两个字符串相同位置的字符进行求和
  • 若是和 >=2,说说明发生了进位,保存进位状态为true,下一次求和要 + 1
  • 若是和 < 2,说明没有发生进位,保存进位状态为false,下一次求和要 + 0
  • 遍历结束后,若是进位状态为 true, 说明第一位字符串仍然发生了进位,则拼上一个1
  • 时间复杂度O(n)
  • 代码:

image.png

7. x 的平方根

实现 int sqrt(int x) 函数。

计算并返回 x 的平方根,其中 x 是非负整数。

因为返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

示例 1:

输入: 4
输出: 2
示例 2:

输入: 8
输出: 2
说明: 8 的平方根是 2.82842...,
  因为返回类型是整数,小数部分将被舍去。
 

解一:

现成的sqrt函数来一个。
image.png

解二:

最耿直的自增暴力解。

image.png
解三:

牛顿法,只用知道迭代公式就行了(原理在数学规划课上学得差很少了):image.png
image.png

8. 爬楼梯

假设你正在爬楼梯。须要 n 阶你才能到达楼顶。

每次你能够爬 1 或 2 个台阶。你有多少种不一样的方法能够爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法能够爬到楼顶。

  1. 1 阶 + 1 阶
  2. 2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法能够爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶
  2. 1 阶 + 2 阶
  3. 2 阶 + 1 阶

解法:动态规划
本问题其实常规解法能够分红多个子问题,爬第n阶楼梯的方法数量,等于 2 部分之和

爬上 n-1n−1 阶楼梯的方法数量。由于再爬1阶就能到第n阶
爬上 n-2n−2 阶楼梯的方法数量,由于再爬2阶就能到第n阶
因此咱们获得公式 dp[n] = dp[n-1] + dp[n-2]dp[n]=dp[n−1]+dp[n−2]
同时须要初始化 dp[0]=1dp[0]=1 和 dp[1]=1dp[1]=1
时间复杂度:O(n)O(n)

image.png

9. 删除排序链表中的重复元素

给定一个排序链表,删除全部重复的元素,使得每一个元素只出现一次。

示例 1:

输入: 1->1->2
输出: 1->2
示例 2:

输入: 1->1->2->3->3
输出: 1->2->3

思路
标签:链表
指定 cur 指针指向头部 head
当 cur 和 cur.next 的存在为循环结束条件,当两者有一个不存在时说明链表没有去重复的必要了
当 cur.val 和 cur.next.val 相等时说明须要去重,则将 cur 的下一个指针指向下一个的下一个,这样就能达到去重复的效果
若是不相等则 cur 移动到下一个位置继续循环
时间复杂度:O(n)O(n)

image.png

10. 合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

 

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你能够假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
 

示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

输出: [1,2,2,3,5,6]

解一:

数组拼接后sort排序。缺点是没有利用nums1和nums2自己是有序数组的优点。

image.png

解法二:双指针 + 从后向前
思路
两个数组从小到大排序
且题目要求 修改nums1为合并排好序的nums1+nums2
双指针
两个分别指向两个数组尾部的指针
从后向前
比较两指针位置的值
大的必定是结果数组的最大值
一一填充到 nums1的末尾
遍历完后
当 n > 0 时
说明 nums2 中还有剩余没有比较的数字
将其插入替换 nums1 数组前面n个数字便可

image.png

相关文章
相关标签/搜索