目录
1.字母异位词分组
2.环形链表
3.环形链表2
4.二叉树的中序遍历
5.搜索插入位置
1.字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
排序字符:对于每个字符串,我们将其字符排序,得到一个唯一的 "排序后的字母" 作为该字符串的标识符(key)。
使用哈希表:利用哈希表(unordered_map)来将排序后的字母作为键(key),将相同字母异位词的字符串作为值(value)。如果两个字符串排序后得到相同的结果,它们属于同一组。
最终结果:哈希表中存储了多个键值对,其中每个键对应的值是一个字母异位词列表。
class Solution {
public:vector<vector<string>> groupAnagrams(vector<string>& strs) {unordered_map<string, vector<string>> anagrams;for (const string& str : strs) {string sorted_str = str;sort(sorted_str.begin(), sorted_str.end());anagrams[sorted_str].push_back(str);}vector<vector<string>> result;for (auto& pair : anagrams) {result.push_back(pair.second);}return result;}
};
unordered_map<string, vector<string>> anagrams;:使用哈希表 anagrams 来存储字母异位词。键是排序后的字符串,值是一个包含所有字母异位词的字符串数组。
遍历每个字符串:
对每个字符串 str,我们创建它的副本 sorted_str。
使用 sort() 函数对 sorted_str 进行排序。
将排序后的 sorted_str 作为哈希表的键,原字符串 str 被添加到相应的值(即字母异位词组)中。
提取结果:哈希表中的每个值都是一个字母异位词的组,我们将所有这些组收集到 result 数组中并返回。
2.环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。
初始化:
两个指针 slow 和 fast,都指向链表头部。
slow 每次走一步,fast 每次走两步。
循环遍历:
如果链表没有环,fast 指针最终会到达链表的末尾(即 fast 或 fast->next 为 NULL)。
如果链表有环,fast 指针和 slow 指针一定会相遇,因为 fast 走得比 slow 快,两者最终会在环内某个节点相遇。
判定条件:
如果在某个时刻 slow == fast,说明链表中存在环,返回 true。
如果 fast 指针走到链表末尾,即 fast 或 fast->next 为 NULL,说明链表没有环,返回 false。
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool hasCycle(ListNode *head) {if (!head || !head->next) return false; // 空链表或只有一个节点没有环ListNode *slow = head; // 慢指针ListNode *fast = head; // 快指针while (fast && fast->next) {slow = slow->next; // 慢指针走一步fast = fast->next->next; // 快指针走两步if (slow == fast) {return true; // 快慢指针相遇,说明链表中有环}}return false; // 快指针走到链表末尾,说明无环}
};
3.环形链表2
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
初始化:
设置两个指针 slow 和 fast,都指向链表的头部。
环的检测:
slow 每次移动一步,fast 每次移动两步。
如果链表存在环,slow 和 fast 会在环中相遇。
如果链表没有环,fast 会在没有环的链表中走到 NULL,循环结束。
寻找环的入口:
当 slow 和 fast 相遇时,说明链表中有环。
将 slow 指针保持在相遇点,并将 entry 指针指向链表的头部。
然后,两个指针都以相同的速度(每次一步)移动,直到它们相遇。相遇点就是环的入口节点。
返回值:如果链表有环,返回环的入口节点;如果链表没有环,返回 NULL。
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head) {if (!head || !head->next) return NULL; // 空链表或者只有一个节点没有环ListNode *slow = head; // 慢指针ListNode *fast = head; // 快指针// 检测链表是否有环while (fast && fast->next) {slow = slow->next; // 慢指针走一步fast = fast->next->next; // 快指针走两步if (slow == fast) {// 当快慢指针相遇,说明有环ListNode *entry = head; // 入口指针从头开始while (entry != slow) {entry = entry->next;slow = slow->next;}return entry; // 返回环的入口节点}}return NULL; // 没有环}
};
4.二叉树的中序遍历
给定一个二叉树的根节点root
,返回 它的 中序 遍历 。
如下为代码:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> stk;TreeNode* curr = root;while (curr != nullptr || !stk.empty()) {while (curr != nullptr) {stk.push(curr);curr = curr->left;}curr = stk.top();stk.pop();result.push_back(curr->val);curr = curr->right;}return result;}
};
vector<int> result; 用来存储中序遍历的结果。
stack<TreeNode*> stk; 用来模拟递归过程中访问的栈。
TreeNode* curr = root; 将 curr 初始化为二叉树的根节点,用来遍历树。
while (curr != nullptr || !stk.empty()):这个循环会一直进行,直到遍历完所有节点。条件判断包括两部分:
curr != nullptr:表示当前节点还存在。
!stk.empty():表示栈不为空,说明还有节点待访问。
while (curr != nullptr):这个内层循环将沿着左子树访问,直到当前节点为空。
在每一步,当前节点 curr 会被压入栈中 (stk.push(curr);),然后将 curr 移动到左子节点 (curr = curr->left;)。
当左子树遍历完毕后,栈顶的节点就是当前最左的节点。
curr = stk.top(); 从栈中取出栈顶节点,即当前最左的节点。
stk.pop(); 弹出栈顶节点,因为这个节点已经被访问过。
result.push_back(curr->val); 将当前节点的值添加到结果数组中。
curr = curr->right; 将 curr 移动到右子树节点,继续进行下一个循环。
5.搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n)
的算法。
代码如下所示:
class Solution {
public:int searchInsert(vector<int>& nums, int target) {int left = 0;int right = nums.size() - 1;while (left <= right) {int mid = left + (right - left) / 2; if (nums[mid] == target) {return mid; } else if (nums[mid] < target) {left = mid + 1; } else {right = mid - 1; }}return left;}
};
int left = 0; 和 int right = nums.size() - 1;:初始化左右指针,分别指向数组的头部和尾部。
while (left <= right):这个循环会持续进行,直到找到目标值或确定目标值的插入位置。
int mid = left + (right - left) / 2;:计算中间位置。使用 left + (right - left) / 2 来避免 left + right 可能出现的溢出问题。
if (nums[mid] == target):如果 mid 位置的元素等于目标值,直接返回该索引。
else if (nums[mid] < target):如果 mid 位置的元素小于目标值,目标值应该在 mid 右侧,更新 left = mid + 1。
else:如果 mid 位置的元素大于目标值,目标值应该在 mid 左侧,更新 right = mid - 1。
return left;:如果循环结束时没有找到目标值,left 将指向目标值应该插入的位置。