Frog Position After T Seconds solution and explanation
9 more videos on this problem
Leetcode 1377(Hard) Frog Position After T Seconds : Simple C++ SolutionShivam Patel · 21:39 · 2K views
花花酱 LeetCode 1377. Frog Position After T Seconds - 刷题找工作 EP313Hua Hua · 12:46 · 2K views
LeetCode 1377. Frog Position After T SecondsHappy Coding · 21:28 · 886 views
5355 Frog Position After T SecondsKelvin Chandra · 8:17 · 867 views
Leetcode - 1377 . Frog Position After T Seconds | DFS ApproachRaman Bhari · 17:54 · 503 views
Leetcode Hard 1377 Frog Position After T Seconds - Google Interview QuestionAlgorithmicIQ · 22:19 · 458 views
Leetcode 1377. Frog Position After T SecondsElite Code · 26:43 · 235 views
Day 24/75: Problem Name: Frog Position after T seconds | Leetcode | #75DaysHardLCCodeInsanity · 12:18 · 154 views
Leetcode 1377. Frog Position After T SecondsFearless Learner · 15:40 · 73 views
[LeetCode] 1377. Frog Position After T Seconds (hard)개발자영맨(bluedawnstar) · 19:24 · 50 views
The problem
Given an undirected tree consisting of n vertices numbered from 1 to n. A frog starts jumping from vertex 1. In one second, the frog jumps from its current vertex to another unvisited vertex if they are directly connected. The frog can not jump back to a visited vertex. In case the frog can jump to several vertices, it jumps randomly to one of them with the same probability. Otherwise, when the frog can not jump to any unvisited vertex, it jumps forever on the same vertex.
The edges of the undirected tree are given in the array edges, where edges[i] = [ai, bi] means that exists an edge connecting the vertices ai and bi.
Return the probability that after t seconds the frog is on the vertex target. Answers within 10-5 of the actual answer will be accepted.
Example 1:
Input: n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 2, target = 4 Output: 0.16666666666666666 Explanation: The figure above shows the given graph. The frog starts at vertex 1, jumping with 1/3 probability to the vertex 2 after second 1 and then jumping with 1/2 probability to vertex 4 after second 2. Thus the probability for the frog is on the vertex 4 after 2 seconds is 1/3 * 1/2 = 1/6 = 0.16666666666666666.
Example 2:
Input: n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 1, target = 7 Output: 0.3333333333333333 Explanation: The figure above shows the given graph. The frog starts at vertex 1, jumping with 1/3 = 0.3333333333333333 probability to the vertex 7 after second 1.
Constraints:
1 <= n <= 100edges.length == n - 1edges[i].length == 21 <= ai, bi <= n1 <= t <= 501 <= target <= n
Approach overview
Problem Overview: You are given an undirected tree with n nodes. A frog starts at node 1 and every second jumps to one of its unvisited neighbors with equal probability. After t seconds, compute the probability that the frog is at the target node. The challenge is modeling the probability flow across the tree while respecting the rule that the frog cannot revisit nodes.
Approach 1: Recursive DFS with Probability Tracking (O(n) time, O(n) space)
This approach treats the tree as a probability flow problem. Build an adjacency list and run a DFS from node 1. At each node, count how many unvisited neighbors are available. If the frog has k choices, each branch receives probability current_prob / k. The recursion continues until either the time reaches t or the frog reaches a leaf. Special handling is required when the frog reaches the target before time runs out: the probability is valid only if the node has no unvisited neighbors left (the frog stays put). DFS works well because it naturally follows paths while carrying probability and time as parameters. The traversal touches each node once, giving O(n) time and O(n) recursion stack space. This approach fits naturally with problems involving trees and probabilistic branching, similar to many Depth-First Search patterns.
Approach 2: BFS with Level Tracking (O(n) time, O(n) space)
A BFS simulation models the frog’s movement second by second. Start with a queue containing (node=1, probability=1.0). Each BFS level represents one second of time. When processing a node, compute how many unvisited neighbors it has and distribute the probability evenly among them before pushing them into the queue. Mark nodes as visited to enforce the rule that the frog never jumps backward. If a node has no unvisited neighbors, its probability remains at that node for the remaining time steps. BFS is often easier to reason about because the queue already aligns with time progression. Each edge is processed at most once, resulting in O(n) time and O(n) queue storage. This technique is common when working with Breadth-First Search on a graph where state evolves per level.
Recommended for interviews: Both DFS and BFS achieve optimal O(n) complexity. Interviewers usually expect the DFS probability propagation because it shows strong reasoning about tree traversal and branching probabilities. BFS is equally valid and sometimes easier to implement without recursion. Showing both approaches demonstrates that you understand tree traversal patterns and how probability flows through a graph structure.
Approach 1: Recursive DFS with Probability Tracking
This approach uses Depth First Search (DFS) to simulate the frog's jumps. We track the probability of the frog being on a certain vertex at a particular time. Starting from vertex 1, at each step, we recursively move to all unvisited connected vertices, multiplying the probability by the inverse of the number of possible moves. If the time reaches 't', we check if the current position is the target.
def frog_position(n, edges, t, target):
from collections import defaultdict
def dfs(node, prob, time, parent):
if time == t or len(graph[node]) == (1 if node != 1 else 0):
return prob if node == target else 0.0
total_prob = 0.0
num_choices = len(graph[node]) - (1 if node != 1 else 0)
for nei in graph[node]:
if nei == parent:
continue
total_prob += dfs(nei, prob / num_choices, time + 1, node)
return total_prob
graph = defaultdict(list)
for a, b in edges:
graph[a].append(b)
graph[b].append(a)
return dfs(1, 1.0, 0, -1)import java.util.*;
public class Solution {
static class Node {
int vertex;
double probability;
int time;
Node(int v, double p, int t) {
this.vertex = v;
this.probability = p;
this.time = t;
}
}
public double frogPosition(int n, int[][] edges, int t, int target) {
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int[] edge : edges) {
graph.computeIfAbsent(edge[0], k -> new ArrayList<>()).add(edge[1]);
graph.computeIfAbsent(edge[1], k -> new ArrayList<>()).add(edge[0]);
}
return dfs(graph, new Node(1, 1.0, 0), new boolean[n + 1], t, target);
}
private double dfs(Map<Integer, List<Integer>> graph, Node node, boolean[] visited, int t, int target) {
if (node.time == t || graph.get(node.vertex).size() == (node.vertex == 1 ? 0 : 1)) {
return node.vertex == target ? node.probability : 0.0;
}
visited[node.vertex] = true;
double totalProb = 0.0;
int choices = 0;
for (Integer neighbor : graph.get(node.vertex)) {
if (!visited[neighbor]) choices++;
}
for (Integer neighbor : graph.get(node.vertex)) {
if (!visited[neighbor]) {
totalProb += dfs(graph, new Node(neighbor, node.probability / choices, node.time + 1), visited, t, target);
}
}
visited[node.vertex] = false;
return totalProb;
}
}The solution constructs the graph using a dictionary of lists. The recursive function dfs is used to track the probability of the frog reaching the target vertex. It returns the probability of ending at 'target' when time reaches 't'. If we're on a leaf node before time 't', the probability accumulates based on whether the current node is the target or not.
Time Complexity: O(n), as we might need to visit each node once during traversal.
Space Complexity: O(n) for storing the adjacency list of the graph and the recursion stack.
Approach 2: BFS with Level Tracking
This approach uses Breadth First Search (BFS) to explore the tree level by level. At each level, we update the probability of the frog being on a specific vertex. The exploration stops once either reaching 't' time limit or a vertex with no unvisited children if reached earlier.
function frogPosition(n, edges, t, target) {
const graph = {};
for (let [a, b] of edges) {
if (!graph[a]) graph[a] = [];
if (!graph[b]) graph[b] = [];
graph[a].push(b);
graph[b].push(a);
}
const queue = [{ node: 1, prob: 1.0, time: 0 }];
const visited = Array(n + 1).fill(false);
visited[1] = true;
while (queue.length > 0) {
const { node, prob, time } = queue.shift();
if (time === t || (node !== 1 && graph[node].length === 1)) {
if (node === target) return prob;
continue;
}
let neighboursCount = 0;
for (let nei of graph[node]) {
if (!visited[nei]) neighboursCount++;
}
for (let nei of graph[node]) {
if (!visited[nei]) {
visited[nei] = true;
queue.push({ node: nei, prob: prob / neighboursCount, time: time + 1 });
}
}
}
return 0.0;
}using System;
using System.Collections.Generic;
public class Solution {
public double FrogPosition(int n, int[][] edges, int t, int target) {
var graph = new Dictionary<int, List<int>>();
foreach (var edge in edges) {
if (!graph.ContainsKey(edge[0])) graph[edge[0]] = new List<int>();
if (!graph.ContainsKey(edge[1])) graph[edge[1]] = new List<int>();
graph[edge[0]].Add(edge[1]);
graph[edge[1]].Add(edge[0]);
}
var queue = new Queue<(int node, double prob, int time)>();
queue.Enqueue((1, 1.0, 0));
var visited = new bool[n + 1];
visited[1] = true;
while (queue.Count > 0) {
var (node, prob, time) = queue.Dequeue();
if (time == t || (graph[node].Count == 1 && node != 1)) {
if (node == target) return prob;
continue;
}
int choices = 0;
foreach (var nei in graph[node]) {
if (!visited[nei]) choices++;
}
foreach (var nei in graph[node]) {
if (!visited[nei]) {
visited[nei] = true;
queue.Enqueue((nei, prob / choices, time + 1));
}
}
}
return 0.0;
}
}The BFS solution iteratively explores each level of the tree, tracking the probability of reaching each vertex. Queue is used to maintain the current node, its probability, and time. This method ensures each vertex is explored uniformly, sharing the probability among children. The BFS loop ends when either the maximum time is reached, or a leaf node is encountered prematurely.
Time Complexity: O(n), due to each edge being processed once.
Space Complexity: O(n), for queue storage handling vertex levels and visited tracking.
Approach 3: BFS
First, based on the undirected tree edges given in the problem, we construct an adjacency list g, where g[u] represents all adjacent vertices of vertex u.
Then, we define the following data structures:
- Queue
q, used to store the vertices and their probabilities for each round of search. Initially,q = [(1, 1.0)], indicating that the probability of the frog being at vertex1is1.0; - Array
vis, used to record whether each vertex has been visited. Initially,vis[1] = true, and all other elements arefalse.
Next, we start the breadth-first search.
In each round of search, we take out the head element (u, p) of the queue, where u and p represent the current vertex and its probability, respectively. The number of unvisited adjacent vertices of the current vertex u is denoted as cnt.
- If
u = target, it means that the frog has reached the target vertex. At this time, we judge whether the frog reaches the target vertex intseconds, or it reaches the target vertex in less thantseconds but cannot jump to other vertices (i.e.,t=0orcnt=0). If so, returnp, otherwise return0. - If
u neq target, we evenly distribute the probabilitypto all unvisited adjacent vertices ofu, then add these vertices to the queueq, and mark these vertices as visited.
At the end of a round of search, we decrease t by 1, and then continue the next round of search until the queue is empty or t \lt 0.
class Solution {
public:
double frogPosition(int n, vector<vector<int>>& edges, int t, int target) {
vector<vector<int>> g(n + 1);
for (auto& e : edges) {
int u = e[0], v = e[1];
g[u].push_back(v);
g[v].push_back(u);
}
queue<pair<int, double>> q{{{1, 1.0}}};
bool vis[n + 1];
memset(vis, false, sizeof(vis));
vis[1] = true;
for (; q.size() && t >= 0; --t) {
for (int k = q.size(); k; --k) {
auto [u, p] = q.front();
q.pop();
int cnt = g[u].size() - (u != 1);
if (u == target) {
return cnt * t == 0 ? p : 0;
}
for (int v : g[u]) {
if (!vis[v]) {
vis[v] = true;
q.push({v, p / cnt});
}
}
}
}
return 0;
}
};function frogPosition(n: number, edges: number[][], t: number, target: number): number {
const g: number[][] = Array.from({ length: n + 1 }, () => []);
for (const [u, v] of edges) {
g[u].push(v);
g[v].push(u);
}
const q: number[][] = [[1, 1]];
const vis: boolean[] = Array.from({ length: n + 1 }, () => false);
vis[1] = true;
for (; q.length > 0 && t >= 0; --t) {
for (let k = q.length; k > 0; --k) {
const [u, p] = q.shift()!;
const cnt = g[u].length - (u === 1 ? 0 : 1);
if (u === target) {
return cnt * t === 0 ? p : 0;
}
for (const v of g[u]) {
if (!vis[v]) {
vis[v] = true;
q.push([v, p / cnt]);
}
}
}
}
return 0;
}func frogPosition(n int, edges [][]int, t int, target int) float64 {
g := make([][]int, n+1)
for _, e := range edges {
u, v := e[0], e[1]
g[u] = append(g[u], v)
g[v] = append(g[v], u)
}
type pair struct {
u int
p float64
}
q := []pair{{1, 1}}
vis := make([]bool, n+1)
vis[1] = true
for ; len(q) > 0 && t >= 0; t-- {
for k := len(q); k > 0; k-- {
u, p := q[0].u, q[0].p
q = q[1:]
cnt := len(g[u])
if u != 1 {
cnt--
}
if u == target {
if cnt*t == 0 {
return p
}
return 0
}
for _, v := range g[u] {
if !vis[v] {
vis[v] = true
q = append(q, pair{v, p / float64(cnt)})
}
}
}
}
return 0
}Complexity comparison
| Approach | Complexity |
|---|---|
| Recursive DFS with Probability Tracking | Time Complexity: |
| BFS with Level Tracking | Time Complexity: |
| BFS | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Recursive DFS with Probability Tracking | O(n) | O(n) | When exploring paths with probability propagation in trees |
| BFS with Level Tracking | O(n) | O(n) | When modeling movement step-by-step across time levels |
Frequently asked questions
Is Frog Position After T Seconds easy or hard?
The problem is labeled Hard because it combines tree traversal with probability reasoning and time constraints. Many candidates implement DFS or BFS correctly but miss edge cases such as staying at a leaf when time remains. Handling these conditions correctly is what makes the problem challenging.
Frog Position After T Seconds Python/Java solution
Python and Java implementations usually rely on recursive DFS that carries three parameters: current node, elapsed time, and probability. JavaScript and C# implementations often use BFS with a queue storing node and probability pairs. Both styles achieve O(n) time complexity.
How to solve Frog Position After T Seconds in O(n)?
Build an adjacency list for the tree and simulate the frog’s movement using DFS or BFS. At each node, count unvisited neighbors and divide the current probability equally among them. Stop when time reaches t or when a leaf node is reached. Since each node is processed once, the algorithm runs in O(n).
What is the best approach for Frog Position After T Seconds?
The most common solution uses DFS with probability propagation on a tree. Each node distributes its probability equally among unvisited neighbors while tracking elapsed time. This approach runs in O(n) time because every node and edge is processed once. BFS with level tracking provides an equally optimal alternative.
Is Frog Position After T Seconds asked at Google/Amazon/Meta?
Tree traversal and probability propagation problems frequently appear in interviews at companies like Google, Amazon, and Meta. While this exact problem may not always appear verbatim, variations involving BFS or DFS on trees with state tracking are common interview patterns.
What data structure is used in Frog Position After T Seconds?
The core data structure is an adjacency list representing the tree. The traversal uses either a recursion stack for DFS or a queue for BFS. A visited set or parent tracking ensures the frog never revisits nodes, preserving the tree traversal constraint.
What is the time complexity of Frog Position After T Seconds?
The optimal time complexity is O(n), where n is the number of nodes in the tree. Both DFS and BFS traverse each node and edge at most once while distributing probabilities to neighbors. Space complexity is also O(n) due to adjacency lists and recursion stack or queue storage.
