黑板异或游戏
LeetCode810题,黑板上有若干个数字,两位同学轮流擦掉一个数字轮到谁的时候,黑板上所有的数已经是0了,就是谁先获胜。
思路分析:
1.该题需要仔细的分析题意,当前情况分为两种。
2.当前黑板上数异或以后就已经是0了,这时候小红一上来就赢了。
3.当前黑板上的数异或不为0,这时候因为每个人擦的都是最优解,肯定不会让对方获胜,那么就要分为两种情况。
4.当黑板上的数是奇数,那么擦到最后黑板上没有数了,轮到小明上来就直接获胜了。
5.反之为偶数就是小红获胜。
public boolean xorGame(int[] nums) {
int x = 0;
for (int v : nums) x ^= v;
return x == 0 || nums.length % 2 == 0;
}
分割回文串
LeetCode131题,给定一个字符串,将字符串切割成多个部分,要求切割出的部分,必须满足回文串的要求,将所有满足的情况添加到集合。
思路分析:
该题采用深度优先算法,不断的递归判断,将满足字符串加入,遍历到最后一个字符串时,将满足的集合添加进结果中,每次递归结束后,都删除集合中最后一个元素。
private void dfs(List<List<String>> ans, char[] ss, int begin, ArrayList<String> path){
//已经遍历完了整个字符串
if(begin == ss.length){
//将当前集合中的字符填入
ans.add(new ArrayList<>(path));
return;
}
for(int i = begin;i < ss.length;i++){
//判断是否满足回文字符串
if(valid(ss, begin, i)){
//将满足的部分加入
path.add(new String(ss, begin, i - begin + 1));
//从结尾处再次开始
dfs(ans, ss, i + 1, path);
//递归完后删除最后一个元素
path.remove(path.size() - 1);
}
}
}
private boolean valid(char[] ss, int l, int r){
while(l < r) if(ss[l++] != ss[r--]) return false;
return true;
}
T 秒后青蛙的位置
LeetCode1377题,一个无向树中青蛙站在初始节点1上,每过一秒就要跳向当前节点的子节点,只有跳到了叶子点时才不能继续往下跳,因为他不能往回跳,求该青蛙在指定时间中,在目标节点时的概率。
给你一棵由 n 个顶点组成的无向树,顶点编号从 1 到 n。青蛙从 顶点 1 开始起跳。规则如下:
在一秒内,青蛙从它所在的当前顶点跳到另一个 未访问 过的顶点(如果它们直接相连)。
青蛙无法跳回已经访问过的顶点。
如果青蛙可以跳到多个不同顶点,那么它跳到其中任意一个顶点上的机率都相同。
如果青蛙不能跳到任何未访问过的顶点上,那么它每次跳跃都会停留在原地。
无向树的边用数组 edges 描述,其中 edges[i] = [fromi, toi] 意味着存在一条直接连通 fromi 和 toi 两个顶点的边。
返回青蛙在 t 秒后位于目标顶点 target 上的概率。
示例 1:
输入:n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 2, target = 4
输出:0.16666666666666666
解释:上图显示了青蛙的跳跃路径。青蛙从顶点 1 起跳,第 1 秒 有 1/3 的概率跳到顶点 2 ,然后第 2 秒 有 1/2 的概率跳到顶点 4,因此青蛙在 2 秒后位于顶点 4 的概率是 1/3 * 1/2 = 1/6 = 0.16666666666666666 。
示例 2:
输入:n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 1, target = 7
输出:0.3333333333333333
解释:上图显示了青蛙的跳跃路径。青蛙从顶点 1 起跳,有 1/3 = 0.3333333333333333 的概率能够 1 秒 后跳到顶点 7 。
示例 3:
输入:n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 20, target = 6
输出:0.16666666666666666
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/frog-position-after-t-seconds
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路分析:
遍历指定的边,记录每个顶点的父节点,和父节点下有多少子节点,遍历完成后,获得目标节点的父节点,一层一层的往上搜索,直到根节点处结束循环,计算概率值。
//下标为某个元素值,值为当前元素值的父节点
int[] father = new int[n+1];
for (int i = 0; i < father.length; i++) {
//默认自己为自己的父节点
father[i] = i;
}
//记录每个父节点下有多少子节点
int[] width = new int[n+1];
//填充元素
for(int[] e:edges) {
//选择小的元素作为父节点
int fa = Math.min(e[0], e[1]);
int son = Math.max(e[0], e[1]);
//son的父节点为fa
father[son] = fa;
//父节点fa拥有的子节点数+1
width[fa]++;
}
//无向数的层数
int path = 0;
//目标节点的分母值
int product = 1;
//目标数是否为叶子节点
boolean isleaf = width[target]==0? true:false;
//找到目标数的最顶点,这时候它的父节点就是自己
while(target!=father[target]) {
//层数加1,不断的往上查找
path++;
//获得当前目标数的父节点
target = father[target];
//计算当前父节点有多少子节点数
product*=width[target];
}
//如果需要查找的节点是非叶子节点,并且层数小于指定秒数,则该青蛙会继续跳向当前目标的子节点
if (!isleaf&&path<t) {
return 0;
}else if(path>t){
return 0;
}else{
//返回最终的概率值
return 1.0/product;
}