腾讯音乐常考题:剖析热门算法,直击面试痛点
2023-09-10 03:45:33
攻克腾讯音乐面试:深入剖析高频考题
腾讯音乐,互联网音乐巨头,其面试难度一直备受求职者关注。深入了解腾讯音乐常考题,对于求职者成功入职至关重要。本文将深入剖析腾讯音乐各事业部高频考题,提供切实可行的解题思路,助力求职者在面试中脱颖而出。
环形链表 II
题目 给定一个链表,找出并返回环形链表的入口节点。如果链表不存在环,返回 null。
解题思路:
使用哈希表或双指针法。哈希表法将遍历过的节点存储起来,当再次遇到相同节点时即表示存在环。双指针法则利用慢指针和快指针,慢指针每次前进一步,快指针每次前进两步。当快指针追上慢指针时,表示存在环,此时慢指针从头结点重新开始,和快指针同步前进,相遇点即为环形链表的入口。
代码示例(双指针法):
bool hasCycle(ListNode *head) {
ListNode *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}
ListNode *detectCycle(ListNode *head) {
if (!hasCycle(head)) return nullptr;
ListNode *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow;
}
验证 IP 地址
题目: 给定一个字符串,验证其是否为有效的 IP 地址。
解题思路:
将字符串分割成四个部分,逐一判断每个部分是否满足 IP 地址的格式要求。注意,IPv4 地址中每个部分的取值范围为 0-255,IPv6 地址中每个部分的长度不超过 4 个十六进制数字。
代码示例:
bool isValidIP(string ip) {
vector<string> parts;
split(ip, '.', parts);
if (parts.size() != 4) return false;
for (string &part : parts) {
if (part.empty() || part.size() > 4) return false;
for (char c : part) {
if (!isdigit(c)) return false;
}
int num = stoi(part);
if (num < 0 || num > 255) return false;
}
return true;
}
实现 Trie (前缀树)
题目: 实现一个 Trie (前缀树) 数据结构,支持以下操作:
- 插入一个字符串
- 查找一个字符串是否存在
- 查找所有以某一前缀开头的字符串
解题思路:
Trie 是一个树形数据结构,每个节点代表一个字符。从根节点开始,依次将字符串中的字符插入到相应的子节点中。查找一个字符串时,从根节点开始依次查找,直到找到该字符串的最后一个字符所在的节点。查找所有以某一前缀开头的字符串时,从该前缀的最后一个字符所在的节点开始,遍历其所有子节点。
代码示例:
class Trie {
public:
Trie() : root(new TrieNode()) {}
void insert(string &word) {
TrieNode *node = root;
for (char c : word) {
if (!node->children.count(c)) {
node->children[c] = new TrieNode();
}
node = node->children[c];
}
node->isWord = true;
}
bool search(string &word) {
TrieNode *node = root;
for (char c : word) {
if (!node->children.count(c)) {
return false;
}
node = node->children[c];
}
return node->isWord;
}
vector<string> startsWith(string &prefix) {
vector<string> result;
TrieNode *node = root;
for (char c : prefix) {
if (!node->children.count(c)) {
return result;
}
node = node->children[c];
}
dfs(node, prefix, result);
return result;
}
private:
struct TrieNode {
unordered_map<char, TrieNode *> children;
bool isWord = false;
};
TrieNode *root;
void dfs(TrieNode *node, string &prefix, vector<string> &result) {
if (node->isWord) result.push_back(prefix);
for (auto &[c, child] : node->children) {
prefix.push_back(c);
dfs(child, prefix, result);
prefix.pop_back();
}
}
};
网络延迟时间
题目描述: 给定一个网络,每个节点有一个延迟值。求出从一个源节点到其他所有节点的最短延迟时间。
解题思路:
使用 Dijkstra 算法。该算法从源节点开始,逐步扩展到其他节点,并更新节点的最短延迟时间。算法的关键在于使用一个优先队列,将待处理的节点按其最短延迟时间排序,每次从队列中取出最短延迟时间的节点进行扩展。
代码示例:
vector<int> networkDelayTime(vector<vector<int>> &edges, int N, int K) {
unordered_map<int, vector<pair<int, int>>> graph;
for (vector<int> &edge : edges) {
graph[edge[0]].push_back({edge[1], edge[2]});
}
vector<int> dist(N + 1, INT_MAX);
dist[K] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, K});
while (!pq.empty()) {
int d = pq.top().first;
int node = pq.top().second;
pq.pop();
if (d > dist[node]) continue;
for (pair<int, int> &neighbor : graph[node]) {
int nextNode = neighbor.first;
int nextDist = d + neighbor.second;
if (nextDist < dist[nextNode]) {
dist[nextNode] = nextDist;
pq.push({nextDist, nextNode});
}
}
}
vector<int> result;
for (int i = 1; i <= N; i++) {
if (dist[i] == INT_MAX) {
result.push_back(-1);
} else {
result.push_back(dist[i]);
}
}
return result;
}
合并 K 个排序链表
题目描述: 合并 K 个已排序的链表为一个新的排序链表。
解题思路:
可以使用分治法或优先队列法。分治法将链表递归地分成较小的部分,然后合并较小的部分。优先队列法则将 K 个链表的头部节点加入优先队列,每次取出优先队列中的最小节点,并将其下一个节点加入优先队列,直到所有节点都处理完。
代码示例(优先队列法):
ListNode *mergeKLists(vector<ListNode *> &lists) {
if (lists.empty()) return nullptr;
ListNode *dummy = new ListNode(0);
ListNode *curr = dummy;
priority_queue<ListNode *, vector<ListNode *>, greater<ListNode *>> pq;
for (ListNode *head : lists) {
if (head) pq.push(head);
}
while (!pq.empty()) {
ListNode *top = pq.top();
pq.pop();
curr->next = top;
curr = curr->next;
if (top->next) pq.push(top->next);
}
return dummy->next;
}
反转链表
题目描述: 给定一个链表,反转其链表。
解题思路:
可以使用递归或迭代法。递归法通过反转子链表来实现链表的反转。迭代法则使用三个指针,一个指向当前节点,一个指向其前一个节点,一个指向其后一个节点。通过指针的移动和交换