Number of possible paths in android pattern lock - search

How many paths possible in android pattern lock?
I thought it can be calculated simply by factorial, with formula (9!)/(9-length)!
Examples:
For length 9, there are 9*8*7*6*5*4*3*2*1 paths.
For length 8, there are 9*8*7*6*5*4*3*2 paths.
For length 7, there are 9*8*7*6*5*4*3 paths.
etc.
Here is the code for calculating this:
def paths_of_length(number_of_staring_points, length_of_path):
print("number_of_staring_points", number_of_staring_points, "length_of_path", length_of_path)
different_paths = 1
for choosing_from in range(number_of_staring_points,
number_of_staring_points - length_of_path,
-1):
different_paths = different_paths * choosing_from
return different_paths
def android_paths():
"""
Returns number of different android lockscreen paths
"""
different_paths = 0
minimum_length = 4
maximum_length = 9
number_of_staring_points = 9
for length in range(minimum_length,maximum_length + 1):
different_paths += paths_of_length(number_of_staring_points,length)
return different_paths
if __name__ == '__main__':
import doctest
doctest.testmod()
print(android_paths())
Is my method, and the code correct? Or am I calculating it wrong?
Thanks in advance.

Update: Found this has been covered in another post android lock password combinations
The allowed moves include adjacent (including diagonals), knights (e.g. 1->6) and pegged moves (e.g. 1->3 if 2 already in the path).
So a quick brute force in python:
pegs = {
1: {3:2, 7:4, 9:5},
2: {8:5},
3: {1:2, 7:5, 9:6},
4: {6:5},
5: {},
6: {4:5},
7: {1:4, 3:5, 9:8},
8: {2:5},
9: {1:5, 3:6, 7:8}
}
def next_steps(path):
return (n for n in range(1,10) if (not path or n not in path and
(n not in pegs[path[-1]]
or pegs[path[-1]][n] in path)))
def patterns(path, steps, verbose=False):
if steps == 0:
if verbose: print(path)
return 1
return sum(patterns(path+[n], steps-1, verbose) for n in next_steps(path))
[(steps, patterns([], steps)) for steps in range(1,10)]
Output:
[(1, 9),
(2, 56),
(3, 320),
(4, 1624),
(5, 7152),
(6, 26016),
(7, 72912),
(8, 140704),
(9, 140704)]
So the total for android (4-9) is:
>>> sum(patterns([], steps) for steps in range(4,10))
389112

Your calculation is wrong, because not every node has edge to another node, and some nodes have some edges only enabled by some conditions.
For example: To reach from top-left node to top-right node, top-middle node should be visited before.
You can't calculate it simply by multiplying some numbers. You need to use a path finding algorithm.
Good news, I wrote one.
Code
This is a utility class:
import java.util.ArrayList;
import java.util.HashMap;
public class Node
{
private String name;
private HashMap<Node, Node> conditionalNeigbors = new HashMap<>();
private ArrayList<Node> neigbors = new ArrayList<>();
private boolean visited = false;
public Node(String name)
{
this.name = name;
}
void addNeigbor(Node n)
{
this.neigbors.add(n);
}
void addConditionalNeigbor(Node condition, Node n)
{
conditionalNeigbors.put(condition, n);
}
ArrayList<Node> getNeigbors(ArrayList<Node> path)
{
ArrayList<Node> toReturn = new ArrayList<>();
ArrayList<Node> conditionals = new ArrayList<>();
for (int i = 0; i < path.size(); i++)
{
if(conditionalNeigbors.containsKey(path.get(i)))
{
conditionals.add(conditionalNeigbors.get(path.get(i)));
}
}
toReturn.addAll(neigbors);
toReturn.addAll(conditionals);
return toReturn;
}
void setVisited(boolean b)
{
visited = b;
}
boolean getVisited()
{
return visited;
}
public String getName()
{
return name;
}
}
And the main class:
import java.util.ArrayList;
public class Pathfinder
{
static boolean debug = false;
/**
* A B C
*
* D E F
*
* G H J
*/
public static void main(String[] args)
{
Node a = new Node("A");
Node b = new Node("B");
Node c = new Node("C");
Node d = new Node("D");
Node e = new Node("E");
Node f = new Node("F");
Node g = new Node("G");
Node h = new Node("H");
Node j = new Node("J");
a.addNeigbor(b);
a.addNeigbor(d);
a.addNeigbor(e);
a.addNeigbor(h);
a.addNeigbor(f);
a.addConditionalNeigbor(b, c);
a.addConditionalNeigbor(d, g);
a.addConditionalNeigbor(e, j);
b.addNeigbor(a);
b.addNeigbor(d);
b.addNeigbor(e);
b.addNeigbor(f);
b.addNeigbor(c);
b.addNeigbor(g);
b.addNeigbor(j);
b.addConditionalNeigbor(e, h);
c.addNeigbor(b);
c.addNeigbor(e);
c.addNeigbor(f);
c.addNeigbor(d);
c.addNeigbor(h);
c.addConditionalNeigbor(b, a);
c.addConditionalNeigbor(e, g);
c.addConditionalNeigbor(f, j);
d.addNeigbor(a);
d.addNeigbor(b);
d.addNeigbor(e);
d.addNeigbor(g);
d.addNeigbor(h);
d.addNeigbor(c);
d.addNeigbor(j);
d.addConditionalNeigbor(e, f);
e.addNeigbor(a);
e.addNeigbor(b);
e.addNeigbor(c);
e.addNeigbor(d);
e.addNeigbor(f);
e.addNeigbor(g);
e.addNeigbor(h);
e.addNeigbor(j);
f.addNeigbor(c);
f.addNeigbor(b);
f.addNeigbor(e);
f.addNeigbor(h);
f.addNeigbor(j);
f.addNeigbor(a);
f.addNeigbor(g);
f.addConditionalNeigbor(e, d);
g.addNeigbor(d);
g.addNeigbor(e);
g.addNeigbor(h);
g.addNeigbor(b);
g.addNeigbor(f);
g.addConditionalNeigbor(d, a);
g.addConditionalNeigbor(e, c);
g.addConditionalNeigbor(h, j);
h.addNeigbor(d);
h.addNeigbor(e);
h.addNeigbor(f);
h.addNeigbor(g);
h.addNeigbor(j);
h.addNeigbor(a);
h.addNeigbor(c);
h.addConditionalNeigbor(e, b);
j.addNeigbor(f);
j.addNeigbor(e);
j.addNeigbor(h);
j.addNeigbor(d);
j.addNeigbor(b);
j.addConditionalNeigbor(h, g);
j.addConditionalNeigbor(f, c);
j.addConditionalNeigbor(e, a);
ArrayList<Node> graph = new ArrayList<>();
graph.add(a);
graph.add(b);
graph.add(c);
graph.add(d);
graph.add(e);
graph.add(f);
graph.add(g);
graph.add(h);
graph.add(j);
int sum = 0;
System.out.println(countPaths(b, 3, new ArrayList<>()));
for (int k = 1; k < 10; k++)
{
for (int i = 0; i < graph.size(); i++)
{
sum += countPaths(graph.get(i), k, new ArrayList<>());
}
System.out.println("Number of all paths with length of " + k + ": " + sum);
sum = 0;
}
}
/*
Finds number of all possible paths of given length, starting from given node
*/
static int countPaths(Node start, int length, ArrayList<Node> path)
{
start.setVisited(true);
path.add(start);
ArrayList<Node> neigbors = start.getNeigbors(path);
int neigborCount = neigbors.size();
ArrayList<Node> unvisitedNeighbors = new ArrayList<>();
for (int i = 0; i < neigborCount; i++)
{
Node temp = neigbors.get(i);
if (temp.getVisited() == false)
{
unvisitedNeighbors.add(temp);
}
}
int unvisitedNeighborCount = unvisitedNeighbors.size();
if (length == 1) // Base case, no more moves, a path found, return 1
{
if (debug)
{
for (int i = 0; i < path.size(); i++)
{
System.out.print(path.get(i).getName());
}
System.out.println("");
}
start.setVisited(false); // Backtrack
path.remove(path.size() - 1);
return 1;
} else // There are still moves
{
int sum = 0;
for (int i = 0; i < unvisitedNeighborCount; i++)
{
sum += countPaths(unvisitedNeighbors.get(i), length - 1, path);
}
start.setVisited(false); // Backtrack
path.remove(path.size() - 1);
return sum;
}
}
}
No, you don't have to run this. I have calculated all for you:
Number of all paths with length of 1: 9
Number of all paths with length of 2: 56
Number of all paths with length of 3: 320
Number of all paths with length of 4: 1624
Number of all paths with length of 5: 7152
Number of all paths with length of 6: 26016
Number of all paths with length of 7: 72912
Number of all paths with length of 8: 140704
Number of all paths with length of 9: 140704
Explanation
I turned the problem into a undirected cyclic graph search problem.
A B C
D E F
G H J
Points are represented as Nodes
Legal moves are represented as Edges
Every Node has a visited property
There are two types of edges: Always available ones, and conditional ones. An example to conditional move: A-C possible only when B is visited.
Search starts from a given node for given length of paths, with empty path. In each iteration, algorithm obtains possible edges(taking account of conditional edges) and recursively calls a sub-search starting from next nodes.
Example
This is an example call trace, for searching paths length of 3, starting from node B.
_\ countPaths(B, 3, null)
_\ countPaths(A, 2, B)
_\ countPaths(C, 1, BA)
_\ countPaths(D, 1, BA)
_\ countPaths(E, 1, BA)
_\ countPaths(F, 1, BA)
_\ countPaths(H, 1, BA)
_\ countPaths(C, 2, B)
_\ countPaths(A, 1, BC)
_\ countPaths(D, 1, BC)
_\ countPaths(H, 1, BC)
_\ countPaths(E, 1, BC)
_\ countPaths(F, 1, BC)
_\ countPaths(D, 2, B)
_\ countPaths(A, 1, BD)
_\ countPaths(E, 1, BD)
_\ countPaths(G, 1, BD)
_\ countPaths(H, 1, BD)
_\ countPaths(C, 1, BD)
_\ countPaths(J, 1, BD)
_\ countPaths(E, 2, B)
_\ countPaths(A, 1, BE)
_\ countPaths(C, 1, BE)
_\ countPaths(D, 1, BE)
_\ countPaths(F, 1, BE)
_\ countPaths(G, 1, BE)
_\ countPaths(H, 1, BE)
_\ countPaths(J, 1, BE)
_\ countPaths(F, 2, B)
_\ countPaths(C, 1, BF)
_\ countPaths(E, 1, BF)
_\ countPaths(H, 1, BF)
_\ countPaths(J, 1, BF)
_\ countPaths(A, 1, BF)
_\ countPaths(G, 1, BF)
_\ countPaths(G, 2, B)
_\ countPaths(D, 1, BG)
_\ countPaths(E, 1, BG)
_\ countPaths(H, 1, BG)
_\ countPaths(F, 1, BG)
_\ countPaths(J, 2, B)
_\ countPaths(F, 1, BJ)
_\ countPaths(E, 1, BJ)
_\ countPaths(H, 1, BJ)
_\ countPaths(D, 1, BJ)
So it simply divides problems into smaller sub-problems, until it gets a problem with length of 1 where solution is 1(base case).
So after finding all path from a given node, all we need to do is to enumerate this operation for all 9 nodes, which is done by a simple for loop in main() method, simply by calling countPaths() methods.

Related

Sum of Two Arrays - Python

Two random integer arrays/lists have been given as ARR1 and ARR2 of size N and M respectively. Both the arrays/lists contain numbers from 0 to 9(i.e. single digit integer is present at every index). The idea here is to represent each array/list as an integer in itself of digits N and M.
You need to find the sum of both the input arrays/list treating them as two integers and put the result in another array/list i.e. output array/list will also contain only single digit at every index.
NOTE:
The sizes N and M can be different.
Output array/list(of all 0s) has been provided as a function argument. Its size will always be one more than the size of the bigger array/list. Place 0 at the 0th index if there is no carry.
No need to print the elements of the output array/list.
def sumOfTwoArrays(arr1, n, arr2, m, output) :
#Your code goes here
#Taking Input Using Fast I/O
def takeInput() :
n = int(stdin.readline().rstrip())
if n == 0 :
return list(), 0
arr = list(map(int, stdin.readline().rstrip().split(" ")))
return arr, n
#to print the array/list
def printList(arr, n) :
for i in range(n) :
print(arr[i], end = " ")
print()
#main
t = int(stdin.readline().rstrip())
while t > 0 :
arr1, n = takeInput()
arr2, m = takeInput()
outputSize = (1 + max(n, m))
output = outputSize * [0]
sumOfTwoArrays(arr1, n, arr2, m, output)
printList(output, outputSize)
t -= 1
Sample Input:
1
3
6 2 4
3
7 5 6
Sample Output:
1 3 8 0
This problem can be solved by a simple function like this:
(Note - you can made adjustment on the last line of return result if needed to meet the "strange requirement" of - 'place 0 at the 0th index if there is no carry'. It's left as a trivial exercise. )
def sum_two_array(L1, L2):
carry, total = 0, 0
m, n = len(L1), len(L2)
k = max(m, n)
result = [0] + [0] * k # add +1
for i in range(1, k+1):
a = L1[m-i] if m - i >= 0 else 0
b = L2[n-i] if n - i >= 0 else 0
total = a + b + carry
result[k-i + 1] = total % 10
carry = total // 10
if carry > 0: result[0] = carry
return result if result[0] != 0 else result[1:]
if __name__ == '__main__':
L1 = [6, 4, 4]
L2 = [7, 5, 6]
print(sum_two_array(L1, L2)) # [1, 4, 0, 0]
print(sum_two_array([6, 2, 4], [7, 5, 6])) # [1, 3, 8, 0]
print(sum_two_array([1, 2, 4], [8, 0])) # [2, 0, 4]
JAVA CODE:
import java.lang.Math;
public class Solution {
public static void sumOfTwoArrays(int arr1[], int arr2[], int output[]) {
int n = arr1.length; //size of arr1
int m = arr2.length; //size of arr2
int o = n+1; //size of output array
int sum1 = 0, sum2=0, totalSum=0;
//storing sum of arr1 in sum1
for(int i=0; i<n; i++)
{
sum1+= arr1[i] * Math.pow(10,(n-1-i));
}
//storing sum of arr2 in sum2
for(int i=0; i<m; i++)
{
sum2+= arr2[i] * Math.pow(10, (m-1-i));
}
totalSum = sum1+sum2;
//storing totalSum in reverse order in output array
for(int i=o-1; i>=0; i--)
{
output[i] = totalSum % 10;
totalSum = totalSum/10;
}
}
}
Explanation:
condition: arr1[n], arr2[m], output[n+1]
Instead of calculating sum of unit, tens, and so on digits of both the arrays.
we first calculate the sum1 of arr1, and sum2 of arr2, by using:
number at index * (10 ^ ((n-1) - index)) concept.
sum1 and sum2 are equal to the n and m sized numbers of respective arrays
we store totalSum = sum1+sum2
we store totalSum's every digit in output[n+1] array
we store it in reverse order by using % and / operations

Calculating number of minimum swaps to sort array (selection sort is too slow) [duplicate]

I'm working on sorting an integer sequence with no identical numbers (without loss of generality, let's assume the sequence is a permutation of 1,2,...,n) into its natural increasing order (i.e. 1,2,...,n). I was thinking about directly swapping the elements (regardless of the positions of elements; in other words, a swap is valid for any two elements) with minimal number of swaps (the following may be a feasible solution):
Swap two elements with the constraint that either one or both of them should be swapped into the correct position(s). Until every element is put in its correct position.
But I don't know how to mathematically prove if the above solution is optimal. Anyone can help?
I was able to prove this with graph-theory. Might want to add that tag in :)
Create a graph with n vertices. Create an edge from node n_i to n_j if the element in position i should be in position j in the correct ordering. You will now have a graph consisting of several non-intersecting cycles. I argue that the minimum number of swaps needed to order the graph correctly is
M = sum (c in cycles) size(c) - 1
Take a second to convince yourself of that...if two items are in a cycle, one swap can just take care of them. If three items are in a cycle, you can swap a pair to put one in the right spot, and a two-cycle remains, etc. If n items are in a cycle, you need n-1 swaps. (This is always true even if you don't swap with immediate neighbors.)
Given that, you may now be able to see why your algorithm is optimal. If you do a swap and at least one item is in the right position, then it will always reduce the value of M by 1. For any cycle of length n, consider swapping an element into the correct spot, occupied by its neighbor. You now have a correctly ordered element, and a cycle of length n-1.
Since M is the minimum number of swaps, and your algorithm always reduces M by 1 for each swap, it must be optimal.
All the cycle counting is very difficult to keep in your head. There is a way that is much simpler to memorize.
First, let's go through a sample case manually.
Sequence: [7, 1, 3, 2, 4, 5, 6]
Enumerate it: [(0, 7), (1, 1), (2, 3), (3, 2), (4, 4), (5, 5), (6, 6)]
Sort the enumeration by value: [(1, 1), (3, 2), (2, 3), (4, 4), (5, 5), (6, 6), (0, 7)]
Start from the beginning. While the index is different from the enumerated index keep on swapping the elements defined by index and enumerated index. Remember: swap(0,2);swap(0,3) is the same as swap(2,3);swap(0,2)
swap(0, 1) => [(3, 2), (1, 1), (2, 3), (4, 4), (5, 5), (6, 6), (0, 7)]
swap(0, 3) => [(4, 4), (1, 1), (2, 3), (3, 2), (5, 5), (6, 6), (0, 7)]
swap(0, 4) => [(5, 5), (1, 1), (2, 3), (3, 2), (4, 4), (6, 6), (0, 7)]
swap(0, 5) => [(6, 6), (1, 1), (2, 3), (3, 2), (4, 4), (5, 5), (0, 7)]
swap(0, 6) => [(0, 7), (1, 1), (2, 3), (3, 2), (4, 4), (5, 5), (6, 6)]
I.e. semantically you sort the elements and then figure out how to put them to the initial state via swapping through the leftmost item that is out of place.
Python algorithm is as simple as this:
def swap(arr, i, j):
arr[i], arr[j] = arr[j], arr[i]
def minimum_swaps(arr):
annotated = [*enumerate(arr)]
annotated.sort(key = lambda it: it[1])
count = 0
i = 0
while i < len(arr):
if annotated[i][0] == i:
i += 1
continue
swap(annotated, i, annotated[i][0])
count += 1
return count
Thus, you don't need to memorize visited nodes or compute some cycle length.
For your reference, here is an algorithm that I wrote, to generate the minimum number of swaps needed to sort the array. It finds the cycles as described by #Andrew Mao.
/**
* Finds the minimum number of swaps to sort given array in increasing order.
* #param ar array of <strong>non-negative distinct</strong> integers.
* input array will be overwritten during the call!
* #return min no of swaps
*/
public int findMinSwapsToSort(int[] ar) {
int n = ar.length;
Map<Integer, Integer> m = new HashMap<>();
for (int i = 0; i < n; i++) {
m.put(ar[i], i);
}
Arrays.sort(ar);
for (int i = 0; i < n; i++) {
ar[i] = m.get(ar[i]);
}
m = null;
int swaps = 0;
for (int i = 0; i < n; i++) {
int val = ar[i];
if (val < 0) continue;
while (val != i) {
int new_val = ar[val];
ar[val] = -1;
val = new_val;
swaps++;
}
ar[i] = -1;
}
return swaps;
}
We do not need to swap the actual elements, just find how many elements are not in the right index (Cycle).
The min swaps will be Cycle - 1;
Here is the code...
static int minimumSwaps(int[] arr) {
int swap=0;
boolean visited[]=new boolean[arr.length];
for(int i=0;i<arr.length;i++){
int j=i,cycle=0;
while(!visited[j]){
visited[j]=true;
j=arr[j]-1;
cycle++;
}
if(cycle!=0)
swap+=cycle-1;
}
return swap;
}
#Archibald, I like your solution, and such was my initial assumptions that sorting the array would be the simplest solution, but I don't see the need to go through the effort of the reverse-traverse as I've dubbed it, ie enumerating then sorting the array and then computing the swaps for the enums.
I find it simpler to subtract 1 from each element in the array and then to compute the swaps required to sort that list
here is my tweak/solution:
def swap(arr, i, j):
tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
def minimum_swaps(arr):
a = [x - 1 for x in arr]
swaps = 0
i = 0
while i < len(a):
if a[i] == i:
i += 1
continue
swap(a, i, a[i])
swaps += 1
return swaps
As for proving optimality, I think #arax has a good point.
// Assuming that we are dealing with only sequence started with zero
function minimumSwaps(arr) {
var len = arr.length
var visitedarr = []
var i, start, j, swap = 0
for (i = 0; i < len; i++) {
if (!visitedarr[i]) {
start = j = i
var cycleNode = 1
while (arr[j] != start) {
j = arr[j]
visitedarr[j] = true
cycleNode++
}
swap += cycleNode - 1
}
}
return swap
}
I really liked the solution of #Ieuan Uys in Python.
What I improved on his solution;
While loop is iterated one less to increase speed; while i < len(a) - 1
Swap function is de-capsulated to make one, single function.
Extensive code comments are added to increase readability.
My code in python.
def minimumSwaps(arr):
#make array values starting from zero to match index values.
a = [x - 1 for x in arr]
#initialize number of swaps and iterator.
swaps = 0
i = 0
while i < len(a)-1:
if a[i] == i:
i += 1
continue
#swap.
tmp = a[i] #create temp variable assign it to a[i]
a[i] = a[tmp] #assign value of a[i] with a[tmp]
a[tmp] = tmp #assign value of a[tmp] with tmp (or initial a[i])
#calculate number of swaps.
swaps += 1
return swaps
Detailed explanation on what code does on an array with size n;
We check every value except last one (n-1 iterations) in the array one by one. If the value does not match with array index, then we send this value to its place where index value is equal to its value. For instance, if at a[0] = 3. Then this value should swap with a[3]. a[0] and a[3] is swapped. Value 3 will be at a[3] where it is supposed to be. One value is sent to its place. We have n-2 iteration left. I am not interested what is now a[0]. If it is not 0 at that location, it will be swapped by another value latter. Because that another value also exists in a wrong place, this will be recognized by while loop latter.
Real Example
a[4, 2, 1, 0, 3]
#iteration 0, check a[0]. 4 should be located at a[4] where the value is 3. Swap them.
a[3, 2, 1, 0, 4] #we sent 4 to the right location now.
#iteration 1, check a[1]. 2 should be located at a[2] where the value is 1. Swap them.
a[3, 1, 2, 0, 4] #we sent 2 to the right location now.
#iteration 2, check a[2]. 2 is already located at a[2]. Don't do anything, continue.
a[3, 1, 2, 0, 4]
#iteration 3, check a[3]. 0 should be located at a[0] where the value is 3. Swap them.
a[0, 1, 2, 3, 4] #we sent 0 to the right location now.
# There is no need to check final value of array. Since all swaps are done.
Nicely done solution by #bekce. If using C#, the initial code of setting up the modified array ar can be succinctly expressed as:
var origIndexes = Enumerable.Range(0, n).ToArray();
Array.Sort(ar, origIndexes);
then use origIndexes instead of ar in the rest of the code.
Swift 4 version:
func minimumSwaps(arr: [Int]) -> Int {
struct Pair {
let index: Int
let value: Int
}
var positions = arr.enumerated().map { Pair(index: $0, value: $1) }
positions.sort { $0.value < $1.value }
var indexes = positions.map { $0.index }
var swaps = 0
for i in 0 ..< indexes.count {
var val = indexes[i]
if val < 0 {
continue // Already visited.
}
while val != i {
let new_val = indexes[val]
indexes[val] = -1
val = new_val
swaps += 1
}
indexes[i] = -1
}
return swaps
}
This is the sample code in C++ that finds the minimum number of swaps to sort a permutation of the sequence of (1,2,3,4,5,.......n-2,n-1,n)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,i,j,k,num = 0;
cin >> n;
int arr[n+1];
for(i = 1;i <= n;++i)cin >> arr[i];
for(i = 1;i <= n;++i)
{
if(i != arr[i])// condition to check if an element is in a cycle r nt
{
j = arr[i];
arr[i] = 0;
while(j != 0)// Here i am traversing a cycle as mentioned in
{ // first answer
k = arr[j];
arr[j] = j;
j = k;
num++;// reducing cycle by one node each time
}
num--;
}
}
for(i = 1;i <= n;++i)cout << arr[i] << " ";cout << endl;
cout << num << endl;
return 0;
}
Solution using Javascript.
First I set all the elements with their current index that need to be ordered, and then I iterate over the map to order only the elements that need to be swapped.
function minimumSwaps(arr) {
const mapUnorderedPositions = new Map()
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== i+1) {
mapUnorderedPositions.set(arr[i], i)
}
}
let minSwaps = 0
while (mapUnorderedPositions.size > 1) {
const currentElement = mapUnorderedPositions.entries().next().value
const x = currentElement[0]
const y = currentElement[1]
// Skip element in map if its already ordered
if (x-1 !== y) {
// Update unordered position index of swapped element
mapUnorderedPositions.set(arr[x-1], y)
// swap in array
arr[y] = arr[x-1]
arr[x-1] = x
// Increment swaps
minSwaps++
}
mapUnorderedPositions.delete(x)
}
return minSwaps
}
If you have an input like 7 2 4 3 5 6 1, this is how the debugging will go:
Map { 7 => 0, 4 => 2, 3 => 3, 1 => 6 }
currentElement [ 7, 0 ]
swapping 1 with 7
[ 1, 2, 4, 3, 5, 6, 7 ]
currentElement [ 4, 2 ]
swapping 3 with 4
[ 1, 2, 3, 4, 5, 6, 7 ]
currentElement [ 3, 2 ]
skipped
minSwaps = 2
Finding the minimum number of swaps required to put a permutation of 1..N in order.
We can use that the we know what the sort result would be: 1..N, which means we don't actually have to do swaps just count them.
The shuffling of 1..N is called a permutation, and is composed of disjoint cyclic permutations, for example, this permutation of 1..6:
1 2 3 4 5 6
6 4 2 3 5 1
Is composed of the cyclic permutations (1,6)(2,4,3)(5)
1->6(->1) cycle: 1 swap
2->4->3(->2) cycle: 2 swaps
5(->5) cycle: 0 swaps
So a cycle of k elements requires k-1 swaps to put in order.
Since we know where each element "belongs" (i.e. value k belongs at position k-1) we can easily traverse the cycle. Start at 0, we get 6, which belongs at 5,
and there we find 1, which belongs at 0 and we're back where we started.
To avoid re-counting a cycle later, we track which elements were visited - alternatively you could perform the swaps so that the elements are in the right place when you visit them later.
The resulting code:
def minimumSwaps(arr):
visited = [False] * len(arr)
numswaps = 0
for i in range(len(arr)):
if not visited[i]:
visited[i] = True
j = arr[i]-1
while not visited[j]:
numswaps += 1
visited[j] = True
j = arr[j]-1
return numswaps
An implementation on integers with primitive types in Java (and tests).
import java.util.Arrays;
public class MinSwaps {
public static int computate(int[] unordered) {
int size = unordered.length;
int[] ordered = order(unordered);
int[] realPositions = realPositions(ordered, unordered);
boolean[] touchs = new boolean[size];
Arrays.fill(touchs, false);
int i;
int landing;
int swaps = 0;
for(i = 0; i < size; i++) {
if(!touchs[i]) {
landing = realPositions[i];
while(!touchs[landing]) {
touchs[landing] = true;
landing = realPositions[landing];
if(!touchs[landing]) { swaps++; }
}
}
}
return swaps;
}
private static int[] realPositions(int[] ordered, int[] unordered) {
int i;
int[] positions = new int[unordered.length];
for(i = 0; i < unordered.length; i++) {
positions[i] = position(ordered, unordered[i]);
}
return positions;
}
private static int position(int[] ordered, int value) {
int i;
for(i = 0; i < ordered.length; i++) {
if(ordered[i] == value) {
return i;
}
}
return -1;
}
private static int[] order(int[] unordered) {
int[] ordered = unordered.clone();
Arrays.sort(ordered);
return ordered;
}
}
Tests
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MinimumSwapsSpec {
#Test
public void example() {
// setup
int[] unordered = new int[] { 40, 23, 1, 7, 52, 31 };
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(5, minSwaps);
}
#Test
public void example2() {
// setup
int[] unordered = new int[] { 4, 3, 2, 1 };
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(2, minSwaps);
}
#Test
public void example3() {
// setup
int[] unordered = new int[] {1, 5, 4, 3, 2};
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(2, minSwaps);
}
}
Swift 4.2:
func minimumSwaps(arr: [Int]) -> Int {
let sortedValueIdx = arr.sorted().enumerated()
.reduce(into: [Int: Int](), { $0[$1.element] = $1.offset })
var checked = Array(repeating: false, count: arr.count)
var swaps = 0
for idx in 0 ..< arr.count {
if checked[idx] { continue }
var edges = 1
var cursorIdx = idx
while true {
let cursorEl = arr[cursorIdx]
let targetIdx = sortedValueIdx[cursorEl]!
if targetIdx == idx {
break
} else {
cursorIdx = targetIdx
edges += 1
}
checked[targetIdx] = true
}
swaps += edges - 1
}
return swaps
}
Python code
A = [4,3,2,1]
count = 0
for i in range (len(A)):
min_idx = i
for j in range (i+1,len(A)):
if A[min_idx] > A[j]:
min_idx = j
if min_idx > i:
A[i],A[min_idx] = A[min_idx],A[i]
count = count + 1
print "Swap required : %d" %count
In Javascript
If the count of the array starts with 1
function minimumSwaps(arr) {
var len = arr.length
var visitedarr = []
var i, start, j, swap = 0
for (i = 0; i < len; i++) {
if (!visitedarr[i]) {
start = j = i
var cycleNode = 1
while (arr[j] != start + 1) {
j = arr[j] - 1
visitedarr[j] = true
cycleNode++
}
swap += cycleNode - 1
}
}
return swap
}
else for input starting with 0
function minimumSwaps(arr) {
var len = arr.length
var visitedarr = []
var i, start, j, swap = 0
for (i = 0; i < len; i++) {
if (!visitedarr[i]) {
start = j = i
var cycleNode = 1
while (arr[j] != start) {
j = arr[j]
visitedarr[j] = true
cycleNode++
}
swap += cycleNode - 1
}
}
return swap
}
Just extending Darshan Puttaswamy code for current HackerEarth inputs
Here's a solution in Java for what #Archibald has already explained.
static int minimumSwaps(int[] arr){
int swaps = 0;
int[] arrCopy = arr.clone();
HashMap<Integer, Integer> originalPositionMap
= new HashMap<>();
for(int i = 0 ; i < arr.length ; i++){
originalPositionMap.put(arr[i], i);
}
Arrays.sort(arr);
for(int i = 0 ; i < arr.length ; i++){
while(arr[i] != arrCopy[i]){
//swap
int temp = arr[i];
arr[i] = arr[originalPositionMap.get(temp)];
arr[originalPositionMap.get(temp)] = temp;
swaps += 1;
}
}
return swaps;
}
def swap_sort(arr)
changes = 0
loop do
# Find a number that is out-of-place
_, i = arr.each_with_index.find { |val, index| val != (index + 1) }
if i != nil
# If such a number is found, then `j` is the position that the out-of-place number points to.
j = arr[i] - 1
# Swap the out-of-place number with number from position `j`.
arr[i], arr[j] = arr[j], arr[i]
# Increase swap counter.
changes += 1
else
# If there are no out-of-place number, it means the array is sorted, and we're done.
return changes
end
end
end
Apple Swift version 5.2.4
func minimumSwaps(arr: [Int]) -> Int {
var swapCount = 0
var arrayPositionValue = [(Int, Int)]()
var visitedDictionary = [Int: Bool]()
for (index, number) in arr.enumerated() {
arrayPositionValue.append((index, number))
visitedDictionary[index] = false
}
arrayPositionValue = arrayPositionValue.sorted{ $0.1 < $1.1 }
for i in 0..<arr.count {
var cycleSize = 0
var visitedIndex = i
while !visitedDictionary[visitedIndex]! {
visitedDictionary[visitedIndex] = true
visitedIndex = arrayPositionValue[visitedIndex].0
cycleSize += 1
}
if cycleSize > 0 {
swapCount += cycleSize - 1
}
}
return swapCount
}
Go version 1.17:
func minimumSwaps(arr []int32) int32 {
var swap int32
for i := 0; i < len(arr) - 1; i++{
for j := 0; j < len(arr); j++ {
if arr[j] > arr[i] {
arr[i], arr[j] = arr[j], arr[i]
swap++
}else {
continue
}
}
}
return swap
}

Recursively return if the number of lowercase letters in a string is even

I'm trying to write a recursive function that returns true if the number of lowercase letters in a string is even. This is what I have until now:
def is_number_of_lowercase_even(s,low,high):
if (low==high):
return False
if low<high:
left = s[low].islower()
return left and not is_number_of_lowercase_even(s,low+1,high)
I have to stick to the function definition above. Not sure what I'm doing wrong.
Something like this? Divide the range in half. If both halves are even or both halves are odd then the total is even.
def f(s, low, high):
if low == high:
return not s[low].islower()
mid = low + (high - low) // 2
left = f(s, low, mid)
right = f(s, mid + 1, high)
return (left and right) or (not left and not right)
strs = [
"Abc",
"ABc",
"asdf",
"aSdF",
"ASdf",
"AsDF"
]
for s in strs:
print(s, f(s, 0, len(s) - 1))
"""
('Abc', True)
('ABc', False)
('asdf', True)
('aSdF', True)
('ASdf', True)
('AsDF', False)
"""

How to detect the fuzzy edge of a raindrop?

I want to extract the edge of the raindrop.
This is raindrop's photo.
I divide the picture into 8*8 blocks and extract the edges using sobel and canny. Now I can get a rough edge.
This is the edge I got.
I can't get the fuzzy edge of the raindrop.
This fuzzy edge I can't get
//sobel
Mat SobelProcess(Mat src)
{
Mat Output;
Mat grad_x, grad_y, abs_grad_x, abs_grad_y, SobelImage;
Sobel(src, grad_x, CV_16S, 1, 0, CV_SCHARR, 1, 1, BORDER_DEFAULT);
Sobel(src, grad_y, CV_16S, 0, 1, CV_SCHARR, 1, 1, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, Output);
//subtract(grad_x, grad_y, SobelImage);
//convertScaleAbs(SobelImage, Output);
return Output;
}
int main()
{
Mat Src;
Src = imread("rain.bmp",0)
imshow("src", Src);
Mat Gauss;
GaussianBlur(Src, Src, Size(5, 5), 0.5);
imshow("Gauss", Src);
//M * N = 8 * 8
int OtsuThresh[M * N];
vector<Mat>tempThresh = ImageSegment(Src);
for (int i = 0; i < M * N; i++)
{
OtsuThresh[i] = Otsu(tempThresh[i]); //get Otsu Threshold
}
vector<Mat>temp;
temp = ImageSegment(Src);//ImageSegment() is a function to divide the picture into 8*8 blocks
for (int i = 0; i < M * N; i++)
{
temp[i] = SobelProcess(temp[i]);
GaussianBlur(temp[i], temp[i], Size(3, 3), 0.5);
Canny(temp[i], temp[i], OtsuThresh[i] / 3, OtsuThresh[i]);
}
Mat Tem;
Tem = ImageMerge(temp);//ImageMerge() is a function to merge the blocks
imshow("Tem", Tem);
}
Then I use watershed. But I can't use it get an ideal result.

Time Complexity of String Subsequence Recursion

How to calculate the time complexity of the algorithm below? Can someone please explain to me briefly:
public static void print(String prefix, String remaining, int k) {
if (k == 0) {
StdOut.println(prefix);
return;
}
if (remaining.length() == 0) return;
print(prefix + remaining.charAt(0), remaining.substring(1), k-1);
print(prefix, remaining.substring(1), k);
}
public static void main(String[] args) {
String s = "abcdef";
int k = 3;
print("", s, k);
}
Suppose m is the length of prefix, and n is the length of remaining. Then the complexity is given by
T(m, n, k) = Θ(m + n) + T(m + 1, n - 1, k - 1) + T(m, n - 1, k).
The Θ(m + n) term stems from
prefix + remaining.charAt(0), remaining.substring(1)
which, in general will require creating two new strings of lengths about m and n, respectively (this might differ among various implementations).
Beyond that, it's pretty difficult to solve (at least for me), except for some very simple bounds. E.g., it's pretty clear that the complexity is at least exponential in the minimum of the length of the prefix and k, since
T(m, n, k) ≥ 2 T(m, n - 1, k - 1) &Rarr; T(m, n, k) = Ω(2min(n, k)).
Introduction
As the body is O(1), or at least can be rewritten as O(1), we only have to look for how many time the function is called. So the time complexity of this algorithm will be how many times the function will be called in relation to length of input word and length of output prefix.
n - length of input word
k - length of prefix being searched for
I have never done something like this before and common methods for finding time complexity for recursive methods that I know of don't work in this case. I started off by looking how many calls to the function were made depending on n and k to see if I can spot any patterns that might help me.
Gathering data
Using this code snippet (sorry for ugly code):
public static String word = "abcdefghij";
public static int wordLength = word.length();
public static int limit = 10;
public static int access = 0;
System.out.printf("Word length : %6d %6d %6d %6d %6d %6d %6d %6d %6d %6d %6d\n",0,1,2,3,4,5,6,7,8,9,10);
System.out.printf("-----------------------------------------------------------------------------------------------\n");
for(int k = 0; k <= limit; k++) {
System.out.printf("k : %2d - results :", k);
for(int i = 0; i <= limit; i++) {
print("", word.substring(0,i), k);
System.out.printf(", %5d", access);
access=0;
}
System.out.print("\n");
}
print(prefix, remaining, k) {
access++;
... rest of code...
}
From this I got :
Word length : 0 1 2 3 4 5 6 7 8 9 10
-----------------------------------------------------------------------------------------------
k : 0 - results :, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
k : 1 - results :, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21
k : 2 - results :, 1, 3, 7, 13, 21, 31, 43, 57, 73, 91, 111
k : 3 - results :, 1, 3, 7, 15, 29, 51, 83, 127, 185, 259, 351
k : 4 - results :, 1, 3, 7, 15, 31, 61, 113, 197, 325, 511, 771
k : 5 - results :, 1, 3, 7, 15, 31, 63, 125, 239, 437, 763, 1275
k : 6 - results :, 1, 3, 7, 15, 31, 63, 127, 253, 493, 931, 1695
k : 7 - results :, 1, 3, 7, 15, 31, 63, 127, 255, 509, 1003, 1935
k : 8 - results :, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1021, 2025
k : 9 - results :, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2045
k : 10 - results :, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047
At least one call is made in every case as it is the initial call. From here we see that everything on and below main diagonal is called 2min(n, k) + 1 - 1 times, like mentioned by others. That is number of nodes in binary tree.
Each time a the print method is called, two new ones will be called - making a binary tree.
Things get more confusing above the main diagonal though and I failed to see any common pattern.
Graph representation of algorithm
To make it more visual I used graphviz (online version).
Here is code snippet that generates code for given n and k for graphviz (green nodes are ones from where solution was found):
public static String word = "abcde";
public static int wordLength = word.length();
public static int limit = 3;
public static void main(String[] args) {
String rootNode = "\"prefix|remaining|k\"";
StringBuilder graph = new StringBuilder("digraph G { \n node [style=filled];");
print("", word, limit, graph, rootNode);
graph.append("\n\"prefix|remaining|k\" [shape=Mdiamond];\n}");
System.out.println(graph);
}
public static void print(String prefix, String remaining, int k, StringBuilder sb, String parent) {
String currentNode = "\"" + prefix + "|" + (remaining.isEmpty() ? 0 : remaining) + "|" + k + "\"";
sb.append("\n " + parent + "->" + currentNode + ";");
if(k == 0) {
sb.append("\n " + currentNode + "[color=darkolivegreen3];");
return;
}
if (remaining.length() == 0)return;
print(prefix + remaining.charAt(0), remaining.substring(1), k - 1, sb,currentNode);
print(prefix, remaining.substring(1), k, sb, currentNode);
}
Example of graph (n=5, k=3):
digraph G {
node [style=filled];
"prefix|remaining|k"->"|abcde|3";
"|abcde|3"->"a|bcde|2";
"a|bcde|2"->"ab|cde|1";
"ab|cde|1"->"abc|de|0";
"abc|de|0"[color=darkolivegreen3];
"ab|cde|1"->"ab|de|1";
"ab|de|1"->"abd|e|0";
"abd|e|0"[color=darkolivegreen3];
"ab|de|1"->"ab|e|1";
"ab|e|1"->"abe|0|0";
"abe|0|0"[color=darkolivegreen3];
"ab|e|1"->"ab|0|1";
"a|bcde|2"->"a|cde|2";
"a|cde|2"->"ac|de|1";
"ac|de|1"->"acd|e|0";
"acd|e|0"[color=darkolivegreen3];
"ac|de|1"->"ac|e|1";
"ac|e|1"->"ace|0|0";
"ace|0|0"[color=darkolivegreen3];
"ac|e|1"->"ac|0|1";
"a|cde|2"->"a|de|2";
"a|de|2"->"ad|e|1";
"ad|e|1"->"ade|0|0";
"ade|0|0"[color=darkolivegreen3];
"ad|e|1"->"ad|0|1";
"a|de|2"->"a|e|2";
"a|e|2"->"ae|0|1";
"a|e|2"->"a|0|2";
"|abcde|3"->"|bcde|3";
"|bcde|3"->"b|cde|2";
"b|cde|2"->"bc|de|1";
"bc|de|1"->"bcd|e|0";
"bcd|e|0"[color=darkolivegreen3];
"bc|de|1"->"bc|e|1";
"bc|e|1"->"bce|0|0";
"bce|0|0"[color=darkolivegreen3];
"bc|e|1"->"bc|0|1";
"b|cde|2"->"b|de|2";
"b|de|2"->"bd|e|1";
"bd|e|1"->"bde|0|0";
"bde|0|0"[color=darkolivegreen3];
"bd|e|1"->"bd|0|1";
"b|de|2"->"b|e|2";
"b|e|2"->"be|0|1";
"b|e|2"->"b|0|2";
"|bcde|3"->"|cde|3";
"|cde|3"->"c|de|2";
"c|de|2"->"cd|e|1";
"cd|e|1"->"cde|0|0";
"cde|0|0"[color=darkolivegreen3];
"cd|e|1"->"cd|0|1";
"c|de|2"->"c|e|2";
"c|e|2"->"ce|0|1";
"c|e|2"->"c|0|2";
"|cde|3"->"|de|3";
"|de|3"->"d|e|2";
"d|e|2"->"de|0|1";
"d|e|2"->"d|0|2";
"|de|3"->"|e|3";
"|e|3"->"e|0|2";
"|e|3"->"|0|3";
"prefix|remaining|k" [shape=Mdiamond];
}
Number of nodes cut from binary tree
From the example where n = 5 and k = 3 we can see that tree of height 3 and three trees of height 2 were cut off. As we visited each of these trees root nodes we get number of nodes cut from complete binary tree to be 1*(23 - 2) + 3*(22 - 2) = 12
If it were a full binary tree : 25 + 1 - 1 = 63
Number of nodes(calls made to function "print") then comes to 63 - 12 = 51
Result matches one we got by calculating number of calls made to function when n = 5 and k = 3.
Now we have to find how many and how big parts of tree are cut off for every n and k.
From here on I will refer to method call print(prefix + remaining.charAt(0), remaining.substring(1), k-1); as left path or left node (as it is in graphviz graphs) and to print(prefix, remaining.substring(1), k); as right path or right node.
We can see the first, and biggest tree is cut when we go left k times and the height of the tree will be n - k + 1. ( + 1 because we visit the root of the tree we cut).
We can see that every time we take left path k times we get to result no matter how many right paths we took before (or in what order). This is unless the word runs out of letters before we get the k left paths. So we can make maximum of n - k right turns.
Lets take a closer look at example where n = 5 and k = 3:
L - left path
R - right path
The first tree cut we took the paths :
LLL
The next highest trees that will be cut will be ones where we take only one right node, possible combinations are :
RLLL, LRLL, LLRL, LLLR -> three trees of height 2 cut
Here we must note that LLLR is already cut as LLL gave solution in previous step.
To get number of next trees (height 1 -> 0 nodes cut) we'll calculate the possible combinations of two rights and three lefts subtracting already visited paths.
Combinations(5,3) - Combinations(4,3) = 10 - 4 = 6 nodes of height 1
We can see the numbers match green nodes on the example graph.
C(n,k) - combinations of k from n
f(n,k) - number binary tree nodes not visited by algorithm
f(n,k) = (2n-k+1-2) + Σn-ki=1(2n-k-i+1-2)(C(k+i,k) - C(k+i-1,k))
Explanation:
(2n-k+1-2) - the highest tree cut, have to bring it out of summation or we'll have to take negative factorials
Σn-ki=1 - sum of all nodes cut, excluding highest tree as it is already added. (We start adding larger trees first)
(2n-k-i+1-2) - number of nodes cut per tree. n-k+1 is the largest tree, then working down from there up to tree with height "n-k-(n-k)+1 = 1"
(C(k+i,k) - C(k+i-1,k)) - find how many trees of given height there is. First find all possible paths (lefts and rights) and then subtract already visited ones(in previous steps).
Looks awful, but it can be simplified if we assume that k != 0 (If we don't assume that there will be factorials of negative numbers - which is undefined)
Simplified function:
f(n,k) = Σn-ki=0(2n-k-i+1-2)*C(k+i-1,k-1)
Evaluation of accurate time complexity
The time complexity of the function:
O(2n- Σn-ki=0(2n-k-i+1-2)*C(k+i-1,k-1))
Now this looks awful and doesn't give much information. I don't know how to simplify it any further. I've asked about it here. No answer so far though.
But is it even worth considering the f(n,k) part? Probably depends on particular application where it is applied. We can see from the data table that it can considerably affect the algorithms calls depending on the choice of n and k.
To see more visually how much the extra part affects complexity I plotted best time complexity and real complexity on graph.
O(2n- Σn-ki=0(2n-k-i+1-2)*C(k+i-1,k-1)) is the colorful surface.
B(2min(n,k)) is the green surface.
We can see that B(2min(n,k)) overestimates (tells it works much better than it actually does) the function complexity by quite much. It is usually useful to look algorithms worst case complexity which is W(2max(n,k))
O(2n- Σn-ki=0(2n-k-i+1-2)*C(k+i-1,k-1)) is the colorful surface.
B(2min(n,k)) is the green surface.
W(2max(n,k)) is the yellow surface.
Conclusion
Best case complexity: B(2min(n,k))
Accurate complexity : O(2n- Σn-ki=0(2n-k-i+1-2)*C(k+i-1,k-1))
Worst case complexity: W(2max(n,k)) -> often noted as O(2max(n,k))
In my opinion worst case complexity should be used to evaluate the function as accurate is too complex to understand what it means without analyzing it further. I wouldn't use best case complexity because it leaves too much to chance. Unfortunately I can't calculate the average complexity for this. Depending on application of the algorithm, using average might be better for algorithm evaluation.
Suppose m is the length of prefix, and n is the length of remaining. Then the complexity is given by
T(m, n, k) = 1 + n + 1 + T(m + 1, n - 1, k - 1) + T(m, n - 1, k)
Obviously, the function stop when n=0 or k=0. So,
T(r, n, 0) = 1 + r
T(m, 0, k) = 1 + 1 + 1 = 3
Reform equation 1, we got
T(m, n, k) - T(m, n - 1, k) = 2 + n + T(m + 1, n - 1, k - 1)
Replace n by n-1 in equation 1
T(m, n - 1, k) - T(m, n - 2, k) = 2 + (n - 1) + T(m + 1, n - 2, k - 1)
... continue ...
T(m, 1, k) - T(m, 0, k) = 2 + (1) + T(m + 1, 0, k - 1)
Sum them up
T(m, n, k) - T(m, 0, k) = 2(n) + (n-1)(n)/2 + {Summation of a from 0 to n - 1 on T(m + 1, a, k - 1)}
Reform
T(m, n, k) = n2/2 + 3n/2 +3 + {Summation of a from 0 to n - 1 on T(m + 1, a, k - 1)}
I guess we can get the answer by solving the Summation by using the last equation and the leading factor of the equation would be something like nk+1

Resources