Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to find lexicographically smallest string to move from start to destination in Python
Suppose we are at position (0, 0) in the Cartesian plane and want to reach point (x, y) using only horizontal (H) and vertical (V) moves of single unit. There are multiple possible paths to reach the destination, each comprising H and V moves. We need to find the lexicographically kth smallest path.
For example, to go from (0,0) to (2,2), one possible path is "HVVH". Since 'H' comes before 'V' lexicographically, paths starting with more H's appear earlier in lexicographical order.
Algorithm
The solution uses a greedy approach with combinatorial counting ?
- Calculate how many paths exist if we choose 'H' first
- If k is smaller than this count, choose 'H' and move right
- Otherwise, choose 'V', subtract the count from k, and move up
- Repeat until we reach the destination
Helper Function
First, we define a function to calculate the number of possible paths from current position to destination ?
from math import factorial
def paths(x, y):
if min(x, y) < 0:
return 0
return factorial(x + y) // factorial(x) // factorial(y)
# Test the function
print("Paths from (0,0) to (2,1):", paths(2, 1))
print("Paths from (0,0) to (3,2):", paths(3, 2))
Paths from (0,0) to (2,1): 3 Paths from (0,0) to (3,2): 10
Complete Solution
Now we implement the main algorithm to find the kth lexicographically smallest path ?
from math import factorial
def paths(x, y):
if min(x, y) < 0:
return 0
return factorial(x + y) // factorial(x) // factorial(y)
def solve(x, y, k):
result = []
current_x, current_y = 0, 0
while (current_x, current_y) != (x, y):
# Calculate paths if we choose 'H' next
paths_with_h = paths(x - current_x - 1, y - current_y)
# If we can move right and k is within H-paths range
if current_x + 1 <= x and k <= paths_with_h:
result.append('H')
current_x += 1
else:
# Choose 'V' and adjust k
k -= paths_with_h
result.append('V')
current_y += 1
return ''.join(result)
# Test with the given example
x, y = 3, 3
k = 3
path = solve(x, y, k)
print(f"The {k}rd lexicographically smallest path to ({x}, {y}): {path}")
# Test with more examples
print(f"1st path to (2, 2): {solve(2, 2, 1)}")
print(f"2nd path to (2, 2): {solve(2, 2, 2)}")
print(f"3rd path to (2, 2): {solve(2, 2, 3)}")
The 3rd lexicographically smallest path to (3, 3): HHVVVH 1st path to (2, 2): HHVV 2nd path to (2, 2): HVHV 3rd path to (2, 2): HVVH
How It Works
The algorithm works by making greedy choices at each step ?
- Calculate remaining paths: At each position, calculate how many paths exist if we choose 'H' next
- Make decision: If k is within this count, choose 'H'. Otherwise, choose 'V' and reduce k
- Update position: Move to the new position and repeat
The paths() function uses the combination formula: C(x+y, x) = (x+y)! / (x! * y!) to count the number of ways to arrange x H's and y V's.
Example Walkthrough
For (3,3) with k=3, the algorithm proceeds as follows ?
| Step | Position | Paths with H | k ? paths? | Choice | New k |
|---|---|---|---|---|---|
| 1 | (0,0) | 10 | Yes (3 ? 10) | H | 3 |
| 2 | (1,0) | 5 | Yes (3 ? 5) | H | 3 |
| 3 | (2,0) | 1 | No (3 > 1) | V | 2 |
| 4 | (2,1) | 1 | No (2 > 1) | V | 1 |
| 5 | (2,2) | 0 | Yes (1 ? 1) | V | 1 |
| 6 | (2,3) | - | - | H | - |
Result: "HHVVVH"
Conclusion
This algorithm efficiently finds the kth lexicographically smallest path using combinatorial counting and greedy selection. The time complexity is O(x + y) and space complexity is O(x + y) for storing the result path.
