这是我参与更文挑战的第 26 天,活动详情查看 更文挑战
这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
137. Z 字形变换 (zigzag-conversion)
标签
- 字符串
- 简单
题目
这里不贴题了,leetcode打开就行,题目大意:
将一个给定字符串 s 根据给定的行数 numRows
,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1
输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"
示例 2
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
示例 3
输入:s = "A", numRows = 1
输出:"A"
基本思路
遇到这种问题,就像我们小学做数学找规律题差不多,关键是,找到周期性变化规律。
我们有的条件是
- 我们有行数参数,规定了一共几行
- 我们知道它是 Z 字形走法
- 我们要把所有行的元素给拉出来,也就是要求每个元素应该属于哪行, 这个元素跟周期有什么关系。
我们先找到周期,例如
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
我们该怎么算周期? 想想正玄曲线,一个图像,它最小周期怎么看
(1) 就左边一竖,这都不好拆,都没形成完整周期
P I N
A L S I G
Y A H R
P I
(2) 这个就看着舒服,没错这才是周期
P I N
A L S I G
Y A H R
P I
(3) 多算一个,右边的就少了,同样不能当做周期
P I N
A L S I G
Y A H R
P I
那周期数跟 numRows 的关系呢,上面有 4 行 numRows = 4
,周期我们看是 PAYPAL
6
个,其实应该是 最下面一个重复算两次,要减一,最右边没有够到第一行还要减 1,其实 T = numRows * 2 - 2
下面就是周期性原理,你字符串任意位置都能算出它在周期中的定位,pos = i % T
有了定位,能算出每个元素在哪一行,其实规律在图中也很清楚
在左边向下一竖上
, pos 就是行的对应数字
// 左边数字是行数
0 P I N
1 A L @ I G
2 Y A H &
3 P I
你比如在第二周期里的 @
它在周期中 pos = 7 % 6 = 1
,其实他就是在行数上,没啥好说的
- 关键是
在右边向上一提上
,对应行数就是T - pos
你比如在第二周期里的 &
它在周期中 pos = 10 % 6 = 4
,对应行数就是 6 - 4 = 2
行,在第二行上。
解释够多了,看代码合注释吧
写法实现
var convert = function(s, numRows) {
if (numRows === 1) {
return s
}
// 存放每一行元素,一共有 numRows 行
let rowsArr = new Array(numRows).fill('')
// 这是循环周期
let T = numRows * 2 - 2;
// 当前元素在哪一行上
let curItemRow = 0
// 遍历把 rowsArr 每一行填上,最后连接每一行就行
for (let i = 0; i < s.length; i++) {
// 当前 i 在循环中位置 pos
let pos = i % T;
// 在左边向下一竖上, pos 就是行的对应数字
if (pos < numRows) {
curItemRow = pos
} else {
// 在右边向上一提上, 对应行数就是 T - pos
curItemRow = T - pos
}
// 当前元素拼接到 rowsArr 的对应行数字符串
rowsArr[curItemRow] += s[i]
}
return rowsArr.join('')
};
let s = "PAYPALISHIRING", numRows = 4
console.log(convert(s, numRows))
// 输出:"PINALSIGYAHRPI"
138. 两个数组的交集 II (intersection-of-two-arrays-ii)
标签
- 数组
- 简单
题目
这里不贴题了,leetcode打开就行,题目大意:
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。 我们可以不考虑输出结果的顺序。
基本思路
map 法我在 leetcode 官方解法找了张图,看图 + 代码 理解就好。
还有排序法,先排序,再双指针遍历,也很简单看代码就行。
写法实现
hashMap
var intersect = function(nums1, nums2) {
let [res, map] = [[], new Map()]
for (item of nums1) {
if (map.has(item)) {
let count = map.get(item)
// 如果已经有了,就对应数量 +1
map.set(item, count + 1)
} else {
map.set(item, 1)
}
}
for (it of nums2) {
let count = map.get(it)
if (count > 0) {
// 说明有交集,取出一个,count - 1
res.push(it)
map.set(it, count - 1)
}
}
return res
};
let nums1 = [4,9,5], nums2 = [9,4,9,8,4]
console.log(intersect(nums1, nums2))
排序法
var intersect = function(nums1, nums2) {
// 先排序
nums1.sort((a, b) => a - b)
nums2.sort((a, b) => a - b)
// 在两个指针分别后移找交集
let [res, left, right] = [[], 0, 0]
while (left < nums1.length && right < nums2.length) {
if (nums1[left] === nums2[right]) {
res.push(nums1[left])
left += 1
right += 1
} else if (nums1[left] < nums2[right]) {
left += 1
} else {
right += 1
}
}
return res
};
let nums1 = [1,2,2,1], nums2 = [2,2]
console.log(intersect(nums1, nums2))
另外向大家着重推荐下这个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列
今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友
Or 搜索我的微信号infinity_9368
,可以聊天说地
加我暗号 "天王盖地虎" 下一句的英文
,验证消息请发给我
presious tower shock the rever monster
,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧