问题描述
给你一个混合字符串 s
,请你返回 s
中 第二大 的数字,如果不存在第二大的数字,请你返回 -1
。
混合字符串 由小写英文字母和数字组成。
示例 1:
输入:s = "dfa12321afd"
输出:2
解释:出现在 s 中的数字包括 [1, 2, 3] 。第二大的数字是 2 。
示例 2:
输入:s = "abc1111"
输出:-1
解释:出现在 s 中的数字只包含 [1] 。没有第二大的数字。
力扣原题目地址:https://leetcode.cn/problems/...
思路分析
方式一 先遍历再去重再排序取最后第二大的数
首先字符串中除了有数字字符,也有字母字符。所以我们在遍历的时候,只需保留数字字符,忽略字母字符即可。这里使用字符串的
charCodeAt
方法做一个转换判断即可。字符串0到字符串9分别对应Unicode的是:console.log( '0'.charCodeAt() ) // 48 console.log( '1'.charCodeAt() ) // 49 ...... // 依次递增 console.log( '8'.charCodeAt() ) // 56 console.log( '9'.charCodeAt() ) // 57
- 排除了字母字符以后,遍历拿到的每一个数字字符,都可以追加到数组中去。这样数组中就记录了所有的数字字符
- 然后把数组中的数字字符做一个去重,去完重以后,再做一个排序,再取第二大的数即可。代码如下:
var secondHighest = function (s) {
let arr = [] // 1. 定义一个空数组,用于存储
for (let i = 0; i < s.length; i++) { // 2. 遍历,并剔除字母字符,只保留数字字符
let item = s[i]
if (item.charCodeAt() >= 48 & item.charCodeAt() <= 57) { // charCodeAt()方法过滤
arr.push(item)
}
}
let newArr = Array.from(new Set([...arr])) // 3. 去个重
newArr.sort((a, b) => { // 4. 排个序
return b - a
})
return newArr[1] ? newArr[1] : -1 // 5. 有第二项,就返回第二项,没有就返回-1
};
方式二 定义俩变量表示第一大第二大的数并不断迭代更新
- 定义两个变量用来表示第一大和第二大的数
- 遍历中不断更新第一大和第二大的数字
这种定义变量通过遍历不断对比并比较大小的操作力扣也有类似的题目
- 比如:力扣之第三大的数
- 结合笔者之前的文章,有助于更高的理解:https://segmentfault.com/a/11...
- 本题代码如下:
var secondHighest = function (s) {
let firstMax = -Infinity // 1. 定义一个最大的数变量(大当家)
let secondMax = -Infinity // 2. 定义一个第二大的数变量(二当家)
for (let i = 0; i < s.length; i++) { // 3. 遍历操作
let item = s[i]
if (item.charCodeAt() >= 48 & item.charCodeAt() <= 57) { // 4. 只对数字字符做操作
if (item > firstMax) { // 5. 若新来的这个比大当家还大
secondMax = firstMax // 6. 那么大当家只能屈尊成为二当家了
firstMax = item // 7. 因为新来的成为大当家了
} else if (item == firstMax) { // 8. 若新来的和大当家一样,那就不变吧,忽略之
} else if (item > secondMax) { // 9. 若新来的比二当家大(但是没有大当家大)
secondMax = item // 10. 那大当家就不用换,只需新来的成为二当家即可
}
}
}
// 11. 最后把 二当家返回出去(注意要做一个判断,因为有可能secondMax还是-Infinity)
return secondMax == -Infinity ? -1 : secondMax
};
总结
力扣多刷几题,就会发现,这一题好像之前做过类似的啊。
是的,所以咱们刷题的时候,注意一下,题目分类,这样会事半功倍。
而且对于前端同学,可以优先刷 字符串、数组分类的题目(因为二叉树、链表前端用的会稍微少一些)