Tarjan算法(寻找强连通分量) 铺垫:连通图的两种DFS遍历方式, 在tarjan算法中采用方式2来遍历顶点
顶点X(i,j)其中
i:DFS中x点被访问的时间点
j: x通过可以回溯到的最早时间点
1129 颜色交替的最短路径 给定一个整数 n,即有向图中的节点数,其中节点标记为 0 到 n - 1。图中的每条边为红色或者蓝色,并且可能存在自环或平行边。
给定两个数组 redEdges 和 blueEdges,其中:
redEdges[i] = [ai, bi] 表示图中存在一条从节点 ai 到节点 bi 的红色有向边,
blueEdges[j] = [uj, vj] 表示图中存在一条从节点 uj 到节点 vj 的蓝色有向边。
返回长度为 n 的数组 answer,其中 answer[X] 是从节点 0 到节点 X 的红色边和蓝色边交替出现的最短路径的长度。如果不存在这样的路径,那么 answer[x] = -1。
示例 1:
1 2 输入:n = 3, red_edges = [[0,1],[1,2]], blue_edges = [] 输出:[0,1,-1]
示例 2:
1 2 输入:n = 3, red_edges = [[0,1]], blue_edges = [[2,1]] 输出:[0,1,-1]
提示:
1 <= n <= 100
0 <= redEdges.length, blueEdges.length <= 400
redEdges[i].length == blueEdges[j].length == 2
0 <= ai, bi, uj, vj < n
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 def shortestAlternatingPaths (self, n, redEdges, blueEdges ): """ :type n: int :type redEdges: List[List[int]] :type blueEdges: List[List[int]] :rtype: List[int] """ e=[[] for i in range (n)] for x,y in redEdges: e[x].append((y,0 )) for x,y in blueEdges: e[x].append((y,1 )) ans=[-1 ]*n vis={(0 ,0 ),(0 ,1 )} q=[(0 ,0 ),(0 ,1 )] distance=0 while q: tmp=q q=[] for x,y in tmp: if ans[x]==-1 : ans[x]=distance for p in e[x]: if p[1 ]!=y and p not in vis: vis.add(p) q.append(p) distance+=1 return ans
解题思路:在路径长度都为一情况下,可以用广度优先遍历一遍便是到各个点的最短路径
前缀和 560.和为k的数组个数 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
子数组是数组中元素的连续非空序列。
示例 1:
1 2 输入:nums = [1,1,1], k = 2 输出:2
示例 2:
1 2 输入:nums = [1,2,3], k = 3 输出:2
提示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {public : int subarraySum (vector<int >& nums, int k) { unordered_map<int , int > mp; mp[0 ] = 1 ; int count = 0 , pre = 0 ; for (auto & x:nums) { pre += x; if (mp.find (pre - k) != mp.end ()) { count += mp[pre - k]; } mp[pre]++; } return count; } };
238.除自身以外数组的乘积 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请 不要使用除法, 且在 O(n) 时间复杂度内完成此题。
示例 1:
1 2 输入: nums = [1,2,3,4] 输出: [24,12,8,6]
示例 2:
1 2 输入: nums = [-1,1,0,-3,3] 输出: [0,0,9,0,0]
提示:
2 <= nums.length <= 105
-30 <= nums[i] <= 30
保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内
进阶: 你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution {public: vector<int > productExceptSelf(vector<int >& nums) { int l=nums.size(); vector<int > L(l,0 ),R(l,0 ); L[0 ]=1 ; for (int i=1 ;i<l;i++){ L[i]=L[i-1 ]*nums[i-1 ]; } R[l-1 ]=1 ; for (int i=l-2 ;i>=0 ;i--){ R[i]=R[i+1 ]*nums[i+1 ]; } vector<int >ans(l,0 ); for (int i=0 ;i<l;i++){ ans[i]=L[i]*R[i]; } return ans; } };
优先队列 在C++中,priority_queue是一个容器适配器,它提供了常数时间的最大元素查找。它通常实现为堆。堆是一种数据结构,其中最大(或最小)元素始终位于顶部。priority_queue是一个模板类,定义在头文件中。它有三个模板参数:元素类型、容器类型和比较函数类型(可选)。默认情况下,它使用std::vector作为其底层容器 。
239. 滑动窗口最大值 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
示例 2:
1 2 输入:nums = [1], k = 1 输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution {public : vector<int > maxSlidingWindow (vector<int >& nums, int k) { int n = nums.size (); priority_queue<pair<int , int >> q; for (int i = 0 ; i < k; ++i) { q.emplace (nums[i], i); } vector<int > ans = {q.top ().first}; for (int i = k; i < n; ++i) { q.emplace (nums[i], i); while (q.top ().second <= i - k) { q.pop (); } ans.push_back (q.top ().first); } return ans; } };
动态规划 53.最大子数列和 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组
是数组中的一个连续部分。
示例 1:
1 2 3 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
示例 3:
1 2 输入:nums = [5,4,-1,7,8] 输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public: int maxSubArray(vector<int>& nums) { int pre = 0, maxAns = nums[0]; for (const auto &x: nums) { pre = max(pre + x, x); maxAns = max(maxAns, pre); } return maxAns; } };
代码
测试用例
测试结果
测试结果
56.合并区间 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
1 2 3 输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
1 2 3 输入:intervals = [[1,4],[4,5]] 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
思路:先对vector进行排序,再根据题意插入
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution {public : vector<vector<int >> merge (vector<vector<int >>& intervals) { if (intervals.size () == 0 ) { return {}; } sort (intervals.begin (), intervals.end ()); vector<vector<int >> merged; for (int i = 0 ; i < intervals.size (); ++i) { int L = intervals[i][0 ], R = intervals[i][1 ]; if (!merged.size () || merged.back ()[1 ] < L) { merged.push_back ({L, R}); } else { merged.back ()[1 ] = max (merged.back ()[1 ], R); } } return merged; } };
快慢指针 234.回文列表 给你一个单链表的头节点 head ,请你判断该链表是否为
回文链表
。如果是,返回 true ;否则,返回 false 。
示例 1:
1 2 输入:head = [1,2,2,1] 输出:true
示例 2:
1 2 输入:head = [1,2] 输出:false
提示:
链表中节点数目在范围[1, 105] 内
0 <= Node.val <= 9
进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
尝试用O(1)的空间复杂度进行解答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Solution {public: bool isPalindrome (ListNode* head) { if (head == nullptr) { return true ; } ListNode* firstHalfEnd = endOfFirstHalf(head); ListNode* secondHalfStart = reverseList(firstHalfEnd->next); ListNode* p1 = head; ListNode* p2 = secondHalfStart; bool result = true ; while (result && p2 != nullptr) { if (p1->val != p2->val) { result = false ; } p1 = p1->next; p2 = p2->next; } firstHalfEnd->next = reverseList(secondHalfStart); return result; } ListNode* reverseList (ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr != nullptr) { ListNode* nextTemp = curr->next; curr->next = prev; prev = curr; curr = nextTemp; } return prev; } ListNode* endOfFirstHalf (ListNode* head) { ListNode* fast = head; ListNode* slow = head; while (fast->next != nullptr && fast->next->next != nullptr) { fast = fast->next->next; slow = slow->next; } return slow; } };