📖 综合技巧专题怎么用?

贪心、摩尔投票、三次反转、二分查找——每道题代表一个独立的面试高频技巧。

本专题包含 5 道题,都是外企面试高频真题。每道题按统一结构讲解:

复习建议:先看生活类比理解问题本质,再看思路建立解题框架,最后手写代码 3 遍形成肌肉记忆。面试时先口述思路,确认无误后再写代码。

1FizzBuzz Easy

题目(人话版)

从 1 打印到 15。但:
• 能被 3 整除的打 "Fizz"
• 能被 5 整除的打 "Buzz"
• 能被 3 和 5 同时整除的打 "FizzBuzz"
• 其他的打数字本身

💡 为什么外企爱考这道题?因为它极其简单,但能筛掉一大批"连基础都不过关"的候选人。据说很多面试官用这道题做初筛,能正确写出的人不到 50%。能写出来不丢人,写不出来直接 pass。

陷阱:先判断 3 还是先判断 15?

最常犯的错误:先判断能不能被 3 整除。这样 15 就会先匹配 "Fizz" 而不是 "FizzBuzz"。必须先判断最严格的条件(同时被 3 和 5 整除)

fizzbuzz.js
1
2
3
4
5
6
7
8
9
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 块卖)。

💡 生活类比:你在菜市场买菜,每天价格不一样。你只能买一次卖一次,怎么赚最多?关键:记住到目前为止的最低价,每天算"如果今天卖能赚多少"。

思路:一次遍历,记住历史最低价

遍历每一天 今天比历史最低还低?更新最低 否则算:今天卖能赚多少? 更新最大利润
股价 [7, 1, 5, 3, 6, 4] 的买卖过程 840 Day17 Day21 买入↓ Day35 Day43 Day56 卖出↑ Day64 利润 = 6-1 = 5
绿点=最低价买入,另一个绿点=最高价卖出。中间不管涨跌,只记住历史最低
maxProfit.js
1
2
3
4
5
6
7
8
9
10
11
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
1
2
3
4
5
6
7
8
9
10
11
12
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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。

💡 生活类比:就是查字典!你不会从第一页翻到最后一页——你翻到中间,看你要找的词在前半部分还是后半部分,然后只翻一半。每次砍掉一半,所以叫"二分"。

思路:循环减半

在 [-1, 0, 3, 5, 9, 12] 中找 9 第一步:看中间值 -1 0 3 5 9 12 中间是5,5<9,往右半边找 第二步:只在右半边 [9, 12] 找 9 12 中间就是9!找到了 ✓ 下标=4
二分查找:每次看中间值,目标大就往右找,目标小就往左找
binarySearch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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++ 面试中一定要这么写。

📋 综合技巧专题速查表

#题目难度
1FizzBuzzEasy
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)

← 返回图解算法与模式