📖 综合技巧专题怎么用?
贪心、摩尔投票、三次反转、二分查找——每道题代表一个独立的面试高频技巧。
本专题包含 5 道题,都是外企面试高频真题。每道题按统一结构讲解:
- 题目描述 — 用人话翻译,不用读三遍才懂
- 生活类比 — 把抽象问题变成熟悉的生活场景
- 暴力思路 → 优化思路 — 面试官想看到的思考过程
- IDE 代码 — 带注释的 JS 实现 + 行号
- 复杂度分析 — 时间/空间,面试必问
- 面试加分项 — 能说出来的额外思考
复习建议:先看生活类比理解问题本质,再看思路建立解题框架,最后手写代码 3 遍形成肌肉记忆。面试时先口述思路,确认无误后再写代码。
1FizzBuzz Easy
题目(人话版)
从 1 打印到 15。但:
• 能被 3 整除的打 "Fizz"
• 能被 5 整除的打 "Buzz"
• 能被 3 和 5 同时整除的打 "FizzBuzz"
• 其他的打数字本身
💡 为什么外企爱考这道题?因为它极其简单,但能筛掉一大批"连基础都不过关"的候选人。据说很多面试官用这道题做初筛,能正确写出的人不到 50%。能写出来不丢人,写不出来直接 pass。
陷阱:先判断 3 还是先判断 15?
最常犯的错误:先判断能不能被 3 整除。这样 15 就会先匹配 "Fizz" 而不是 "FizzBuzz"。必须先判断最严格的条件(同时被 3 和 5 整除)。
fizzbuzz.js
function fizzBuzz(n) {
for (let i = 1; i <= n; i++) {
if (i % 15 === 0) console.log('FizzBuzz'); // 必须先判断!
else if (i % 3 === 0) console.log('Fizz');
else if (i % 5 === 0) console.log('Buzz');
else console.log(i);
}
}
// 输出 1~15:
// 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz,
// 11, Fizz, 13, 14, FizzBuzz
面试加分项:写完暴力版后,主动说"我还可以用字符串拼接的方式写,避免多层 if-else":let str = ''; if(i%3===0) str+='Fizz'; if(i%5===0) str+='Buzz'; console.log(str || i);。这种写法扩展性更强——以后要加 "能被 7 整除打 Bazz",只需要加一行 if,不用改整个 if-else 结构。
2买卖股票的最佳时机 (Best Time to Buy/Sell Stock) Easy
题目(人话版)
给你一个股价数组 [7,1,5,3,6,4],第 i 个数是第 i 天的股价。只能买卖一次,最大利润是多少?答案是 5(第 2 天 1 块买,第 5 天 6 块卖)。
💡 生活类比:你在菜市场买菜,每天价格不一样。你只能买一次卖一次,怎么赚最多?关键:记住到目前为止的最低价,每天算"如果今天卖能赚多少"。
思路:一次遍历,记住历史最低价
遍历每一天→
今天比历史最低还低?更新最低→
否则算:今天卖能赚多少?→
更新最大利润
绿点=最低价买入,另一个绿点=最高价卖出。中间不管涨跌,只记住历史最低
maxProfit.js
function maxProfit(prices) {
let minPrice = Infinity; // 到目前为止的最低价
let maxProfit = 0;
for (const price of prices) {
if (price < minPrice) {
minPrice = price; // 发现更低的买入价!
} else {
maxProfit = Math.max(maxProfit, price - minPrice);
}
}
return maxProfit;
}
时间 O(n),空间 O(1)。一次遍历,记住最低价即可。
核心思想:这道题是贪心算法的入门——每一步都做"当前最优"的选择(记住最低价,每天都试着卖),不需要回头看。
3多数元素 (Majority Element) Easy
题目(人话版)
数组里有一个数字出现次数超过一半(> n/2),找出它。[3,2,3] → 答案 3。[2,2,1,1,1,2,2] → 答案 2。
💡 生活类比:想象一个投票现场——A 党派占超过一半的人,B 党派不到一半。你让所有人两两对打(一个 A 碰到一个 B 就同归于尽),最后活下来的一定是多数党,因为多数党人多,怎么配对都剩。这就是"摩尔投票法"。
思路:摩尔投票法(Boyer-Moore)
候选人 = 第一个数,票数=1→
遇到相同的?票数+1→
遇到不同的?票数-1→
票数变0?换候选人
majorityElement.js
function majorityElement(nums) {
let candidate = nums[0];
let count = 1;
for (let i = 1; i < nums.length; i++) {
if (count === 0) {
candidate = nums[i]; // 换候选人
}
count += (nums[i] === candidate) ? 1 : -1;
}
return candidate;
}
| 方法 | 时间 | 空间 | 说明 |
| 哈希表计数 | O(n) | O(n) | 直观但费空间 |
| 排序取中间 | O(n log n) | O(1) | 排完序后中间那个一定是 |
| 摩尔投票法 | O(n) | O(1) | ✅ 最优解 |
面试加分:主动说三种方法,然后说"摩尔投票法最优——O(n) 时间 O(1) 空间"。面试官追问"为什么投票法一定对?"回答:"多数元素超过一半,即使所有其他元素都和它抵消,它也至少剩 1 票。"
4旋转数组 (Rotate Array) Medium
题目(人话版)
把数组往右旋转 k 步。[1,2,3,4,5,6,7] 旋转 3 步 → [5,6,7,1,2,3,4]。
💡 生活类比:就像一排人手拉手转圈——右转 3 步就是最右边 3 个人跑到最左边。关键发现:右转 k 步 = 把最后 k 个搬到前面。
思路:三次反转法(最优雅)
这有个非常巧妙的发现:[1,2,3,4,5,6,7] k=3
整体反转→
[7,6,5,4,3,2,1]
反转前 k 个→
[5,6,7,4,3,2,1]
反转后面的→
[5,6,7,1,2,3,4] ✓
rotate.js
function rotate(nums, k) {
k = k % nums.length; // k 可能比长度大,取余
// 辅助函数:反转 [start, end) 范围
const reverse = (arr, start, end) => {
while (start < end) {
[arr[start], arr[end - 1]] = [arr[end - 1], arr[start]];
start++; end--;
}
};
reverse(nums, 0, nums.length); // 1. 整体反转
reverse(nums, 0, k); // 2. 反转前 k 个
reverse(nums, k, nums.length); // 3. 反转后面的
}
时间 O(n),空间 O(1)。三次反转,原地完成。
细节:k 可能大于数组长度!比如长度 7 旋转 10 步 = 旋转 3 步(转一圈回来一样)。所以第一步 k = k % nums.length 必不可少。
5二分查找 (Binary Search) Easy
题目(人话版)
在一个有序数组 [-1,0,3,5,9,12] 里找数字 9。返回它的下标(答案是 4)。找不到返回 -1。
💡 生活类比:就是查字典!你不会从第一页翻到最后一页——你翻到中间,看你要找的词在前半部分还是后半部分,然后只翻一半。每次砍掉一半,所以叫"二分"。
思路:循环减半
二分查找:每次看中间值,目标大就往右找,目标小就往左找
binarySearch.js
function search(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (nums[mid] === target) {
return mid; // 找到了!
} else if (nums[mid] < target) {
left = mid + 1; // 目标在右半边
} else {
right = mid - 1; // 目标在左半边
}
}
return -1; // 没找到
}
时间 O(log n),空间 O(1)。100万个数最多只需 20 次比较!
大坑:整数溢出。(left + right) / 2 在极端情况下 left+right 可能超过整数最大值。更安全的写法:left + Math.floor((right - left) / 2)。JS 不会有这个问题(数字是浮点),但在 Java/C++ 面试中一定要这么写。
📋 综合技巧专题速查表
| # | 题目 | 难度 |
| 1 | FizzBuzz | Easy |
| 2 | 买卖股票的最佳时机 (Best Time to Buy/Sell Stock) | Easy |
| 3 | 多数元素 (Majority Element) | Easy |
| 4 | 旋转数组 (Rotate Array) | Medium |
| 5 | 二分查找 (Binary Search) | Easy |
考点核心:综合技巧专题的核心就是"用对工具,降复杂度"。
面试时拿到题先想:"这道题能用综合技巧吗?"
如果能,先说思路再写代码,面试官就知道你的分析能力。
🔗 其他考点专题
→ 双指针专题:回文检测 (Valid Palindrome), 反转字符串 (Reverse String), 合并两个有序数组 (Merge Sorted Arrays), 移动零 (Move Zeroes)
→ 哈希表专题:两数之和 (Two Sum), 有效的字母异位词 (Valid Anagram), 数组去重/判断有重复 (Contains Duplicate), 第一个唯一字符 (First Unique Character)
→ 动态规划专题:斐波那契数列 (Fibonacci), 爬楼梯 (Climbing Stairs), 最大子序和 (Max Subarray)
→ 位运算专题:只出现一次的数字 (Single Number), 缺失数字 (Missing Number)
→ 栈与滑动窗口专题:有效括号 (Valid Parentheses), 最长不重复子串 (Longest Substring)
← 返回图解算法与模式