题目描述
给定一个链表,判断链表中是否有环。你能用 O(1)(即,常量)内存解决此问题吗?
题解
用快慢指针的方法。
1 | bool hasCycle(ListNode *head) { |
给定一个链表,判断链表中是否有环。你能用 O(1)(即,常量)内存解决此问题吗?
用快慢指针的方法。
1 | bool hasCycle(ListNode *head) { |
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
利用位运算和有限状态自动机。对32位每位分开看待,按位加,出现三次的对应位加起来一定是3的倍数,所以模3就三种情况:00, 01,10. 模3之后每一位剩下的就是只出现了一次的那个数。余数有两位,记为two, one。int共32位,用两个数twos, ones存放,使用位运算。主要就是用有限自动机,找出如何计算twos和ones了。最后的结果每一位只会是01或00,因此ones的值就是要找的数字。
1 | int singleNumber(vector<int>& nums) { |
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。你需要按照以下要求,帮助老师给这些孩子分发糖果:
那么这样下来,老师至少需要准备多少颗糖果呢?
先向左看,如果a[i]>a[i-1],则有c[i]=c[i-1]+1;否则c[i]=1。再向右看,如果a[i]>a[i+1], 则有c[i]=(c[i], c[i+1]+1).
1 | int candy(vector<int>& ratings) { |
还有波峰波谷一次遍历的方法。
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。
说明:
gas<cost的点一定不会是起点,根据这一点,筛选出可能是起点的编号,然后对每一个编号进行计算模拟行驶过程,若计算中出现负数,则考虑下一个;若结果为非负数,则直接返回。
1 | int canCompleteCircuit(vector<int>& gas, vector<int>& cost) { |
效率低得可怜,但至少是自创。
还看到一个高效巧妙的方法:为了让总油量剩余值(黑色折线)任意部分都不小于0(都在X轴以上),需要向上移动黑色折线,直到所有点都在X轴或X轴以上。此时,处在X轴的点即为出发点。
1 | int canCompleteCircuit(vector<int>& gas, vector<int>& cost) |
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val
(int
) 和其邻居的列表(list[Node]
)。
使用 HashMap 存储所有访问过的节点和克隆节点。HashMap 的 key 存储原始图的节点,value 存储克隆图中的对应节点。visited 用于防止陷入死循环,和获得克隆图的节点。
将第一个节点添加到队列。克隆第一个节点添加到名为 visited 的 HashMap 中。
BFS 遍历
从队列首部取出一个节点。
遍历该节点的所有邻接点。
如果某个邻接点已被访问,则该邻接点一定在 visited 中,那么从 visited 获得该邻接点。
否则,创建一个新的节点存储在 visited 中。
将克隆的邻接点添加到克隆图对应节点(步骤1中得到的首部节点)的邻接表中。
作者:LeetCode
链接:https://leetcode-cn.com/problems/clone-graph/solution/ke-long-tu-by-leetcode/
1 | #include<unordered_map> |
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
使用动态规划的方法,可以利用上次的动态规划判断回文字符串的方法做优化。
dp[i]:前缀子串 s[0:i] (包括索引 i 处的字符)符合要求的最少分割次数
状态转移方程: dp[i] = min(dp[j] + 1 if s[j + 1: i] 是回文 for j in range(i))
1 | int minCut(string s) { |
最初是按照上次的想法稍微改动了一下,结果“超出时间限制”:
1 | bool **dp; |
还是很菜啊……所以更不能一直躺着啊……
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)
从最小的开始往后找。为了去重并把搜索降到O(1),使用unordered_set。
1 | int longestConsecutive(vector<int>& nums) { |
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
分两步。第一步对s使用dp方法确定回文子串。第二步使用回溯法进行分割。
第一步,dp[i][j]代表s(i,j)是否为回文(包含i和j)字符串,注意当ij之间的字符大于等于3个时,dp[i][j]=dp[i+1][j-1]&&s[i]\==s[j],即i递减,j递增,又j>=i,即可确定i,j的递推方向。第二步,dfs(ps),将对dp[ps][i] (ps<=i<n)中为true的,s(ps,i)放入组合,进行dfs,当ps==n时,当前组合放入结果。注意dfs的优化,模版类使用传址,复用变量(如字符串s的大小)使用全局变量。
1 | int len; bool **dp; |
给定一个二维的矩阵,包含 'X'
和 'O'
(字母 O)。
找到所有被 'X'
围绕的区域,并将这些区域里所有的 'O'
用 'X'
填充。
(好像围棋啊……)
题目要求替换所有被包围的’O’,其实可以找出所有未被包围的’O’:绕着矩阵的最外圈转一圈,碰到’O’,就宽度优先搜索,经过的所有’O’都标记为’Y’,最后,将所有的’O’改为’X’,所有的’Y’改为’O’。
不过这样做最大的问题在于时间超限……神奇,解决方案是:每在边框上找到一个’O’,别急着bfs,把所有合适的点都入队之后,再对所有点bfs。这样居然会把时间超限变成用时击败98% !
1 | queue<pair<int, int>> q; |
给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。例如,从根到叶子节点路径 1->2->3 代表数字 123。计算从根到叶子节点生成的所有数字之和。
1 | int helper(TreeNode* root, int i) |
我这是怎么了啊……