PermCheck codility. O(N) time complexity - c#

Hi i have this solution for PermCheck codility. Here is the link which includes the question: https://codility.com/demo/results/demo73YNCU-8FK/
I got 100% for it but i got a time complexity of O(N * log(N)) or O(N).
How could i make this code O(N)? Could you also give a brief description of what makes code O(N)? Thankyou.
Code here for shortcut:
Array.Sort(A);
if(A[0] == 1 && A.Length == 1) return 1;
if(A[0] != 1) return 0;
int n = 0;
for(int i = 0; i < A.Length; i++)
{
if(i < A.Length - 1)
{
if(A[i+1] == A[i] + 1)
{
n += 1;
}
else
{
return 0;
}
}
}
return 1;

Create a bool array which has the same size as the input, N, and leave all elements as the default false value. Loop through every element X of the input. If X is greater than N then return false. If array[N-1] is true, return false. Otherwise set array[N-1] to true. Repeat. This is O(N).
Explanation: First, if you have a permutation, then you need elements 1..N, but if any element is larger than N, then surely some elements are missing. Second, if an element occurs twice, it's a problem, that's why we create the bool array to remember already seen elements.

My python solution (doesn't need additional libraries, looks pythonic and not difficult to understand by others):
def solution(A): return 1 if len(set(A)) == len(A) == sorted(A)[-1] else 0
It can be simplified to:
def solution(A):
if len(set(A)) == len(A):
if len(A) == sorted(A)[-1]:
return 1
return 0
I checked two moments:
1: Length of set from array (set can't have duplicates) is equals to length of initial array
Arrays passed (no duplicates):
[1, 3, 2, 4], [4, 3, 2, 5]
Arrays failed:
[1, 1, 2, 4], [5, 6, 6, 1]
2: Length of initial array is equals to last element in sorted array
Arrays passed:
[1, 2, 3, 4]: Length is equal to last element => return 1
Arrays failed:
[2, 3, 4, 5]: Length is not equal to last element => return 0
This code doesn't work if A contains 0 or negative elements, but according to task details: each element of array A is an integer within the range [1..1,000,000,000].
Codility shows 100% and O(N) or O(N * log(N))
Tried to make it O(N) (suggested by fejesjoco):
def solution(A):
array_length = len(A)
seen_values = [False] * array_length
for x in A:
if x > array_length:
return 0
else:
if seen_values[x - 1]:
return 0
else:
seen_values[x - 1] = True
return 1
Codility result 100% Detected time complexity: O(N) or O(N * log(N))
Both codes shows equal result and time complexity. Maybe codility can't evaluate it right?

Here is my 100/100 answer:
same Idea as #fejesjoco
https://codility.com/demo/results/demoNR485D-33P/
You can change int to long to get performance.
public int solution(int[] A)
{
// idea: add to set,dictionary. Count the size and compare to N.
// dedupe data when needed.
var set = new HashSet<int>();
var max = int.MinValue;
foreach (var item in A)
{
if (set.Contains(item)) return 0;
set.Add(item);
if (item > max) max = item;
}
return set.Count == max ? 1 : 0;
}

This is my solution that scored 100% in correctness and performance.
def solution(A):
arraylength = len(A)
if (arraylength > 100000):
raise ValueError("Out of bound range")
arr = sorted(A)
for i in range(arraylength):
if (arr[i] != i+1):
return 0
return 1

I know that this questions is asked long time ago but it is still active in codility.
Possible solution:
public int solution(int[] A)
{
return (Enumerable.Range(1, A.Length).Except(A).Count() == 0) ? 1 : 0;
}

Following the suggestion by fejesjoco,
Boolean[] bln = new Boolean[A.Length];
for (int i = 0; i < A.Length; i++)
{
if (A[i] > A.Length) // more than array length
return 0;
if (bln[A[i]-1]) // same value twice
return 0;
bln[A[i]-1] = true;
}
return 1;

This was my solution, it scored 100%. Do not forget to add "using System.Linq".
int distinctLength = A.Distinct().ToArray().Length;
// The array length should equal to the distinct array length which is also the maximum value in array A.
if (A.Length == distinctLength && distinctLength == A.Max()) { return 1; }
return 0;

Swift Solution 100%
public func solution(_ A : inout [Int]) -> Int {
// write your code in Swift 4.2.1 (Linux)
let sorted = A.sorted()
for (index, value) in sorted.enumerated() {
if index+1 != value {
return 0
}
}
return 1
}

Related

Get all split options to k chunks

I need to split an array arr into k chunks where the union of all the chucks is arr and there in no same element in two chunks.
For example for
int[] arr = new int[] {1, 2, 3, 4, 5};
int k = 3;
I need to return all the possible splits:
[[1], [2], [3,4,5]]
[[1], [2,3], [4,5]]
[[1], [2,3,4], [5]]
[[1,2], [3], [4,5]]
[[1,2], [3,4], [5]]
[[1,2,3], [4], [5]]
How can I do that efficiently in C#?
You have a combinatoric problem: given an array of n item you should sample k subarrays or, put it differently, k - 1 splits from n - 1:
[A, B, C, D, E] n items, n - 1 possible splits
^ ^
| | k - 1 splits from n - 1 avaialable
| |
[A] [B, C] [D, E] k chunks
Note that we have standard combinatoric problem
k - 1 from n - 1 unordered without repetitions
Code for such sampling can be
private static IEnumerable<int[]> Samples(int take, int from) {
if (take > from || take <= 0 || from <= 0)
yield break;
int[] array = Enumerable.Range(0, take).ToArray();
for (bool agenda = true; agenda; ) {
agenda = false;
yield return array.ToArray();
for (int i = array.Length - 1; i >= 0; --i)
if (array[i] < from - take + i) {
agenda = true;
array[i] += 1;
for (int j = i + 1; j < array.Length; ++j)
array[j] = array[i] + j - i;
break;
}
}
}
Having this sampling routine, we can implement splitting into chunks:
private static IEnumerable<T[][]> MyChunks<T>(T[] array, int take) {
if (take > array.Length)
yield break;
foreach (var sample in Samples(take - 1, array.Length - 1)) {
T[][] result = new T[take][];
for (int i = 0, from = 0, to; i <= sample.Length; ++i, from = to) {
to = i < sample.Length ? sample[i] + 1 : array.Length;
result[i] = array
.Skip(from)
.Take(to - from)
.ToArray();
}
yield return result;
}
}
Demo:
var arr = new int[] { 1, 2, 3, 4, 5};
int k = 3;
string report = string.Join(Environment.NewLine, MyChunks(arr, k)
.Select(chunk => "[" + string.Join(", ", chunk
.Select(item => $"[{string.Join(",", item)}]")) + "]"));
Console.Write(report);
Output:
[[1], [2], [3,4,5]]
[[1], [2,3], [4,5]]
[[1], [2,3,4], [5]]
[[1,2], [3], [4,5]]
[[1,2], [3,4], [5]]
[[1,2,3], [4], [5]]
On way to solve such a problem is to divide and conquer. We could first solve how we compute the possible splits of an array if we only ever wanted to split into two sub arrays (k = 2).
I.e. our function, when given 1,2,3,4, should return 1|2,3,4, 1,2|3,4, and 1,2,3|4 where | marks the border between the left and right subarrays.
Note how the | starts at the left-most position (that still produces a non-empty split on the left) and gradually moves to the right, until no more non-empty split can be produced for the right.
A C# function that does this is shown below:
IEnumerable<(Memory<int>, Memory<int>)> PossibleSplits(
Memory<int> xs) {
for (var i = 1; i < xs.Length; i++)
yield return (xs[..i], xs[i..]);
}
var splits = PossibleSplits(new[] { 1, 2, 3, 4, 5 }.AsMemory());
As you can see it returns a sequence of left/right tuples.
I'm using Memory so no new arrays are allocated when splitting the input data.
One nice property of this function is that it returns an empty sequence when the input array's length is smaller than 2.
So how do we split to an abritrary number of splits, not only 2? One trick is to recursively split the left side of a split again until the left side becomes to small to be split.
To that end we have to modify the above function in several ways:
The return value must change from a sequence of Memory tuples to a sequence of Memory sequences.
i cannot always start at position 1. When splitting into an arbitrary number k of splits, our function must make sure that the left side always holds enough elements for it to be split again into at least k - 1 subarrays. Therefor i must start at k - 1.
Obviously the function needs to call itself to become recursive. And it must do so with one of the two subarrays (we choose left) and the predecssor of k. Decrementing k accounts for the other subarray that won't be split up any further, but will be returned as part of the result of course.
We must add an exit condition to break the recursive cycle. When k is below 2 then we cannot meaningfully split the array (regardless of its size) and just return the input array wrapped as a singleton sequence.
Below is a recursive version of the function above that does just that:
public static class Ext {
public static IEnumerable<IEnumerable<Memory<int>>> PossibleSplits(
this Memory<int> xs,
int k) {
if (k < 2) {
yield return Enumerable.Repeat(xs, 1);
yield break;
}
for (var i = k - 1; i < xs.Length; i++) {
var (left, right) = (xs[..i], xs[i..]);
foreach (var split in left.PossibleSplits(k - 1))
yield return split.Append(right);
}
}
}
var splits = new[] { 1, 2, 3, 4, 5 }
.AsMemory()
.PossibleSplits(k: 3);
It's an extension method, just because I like them.
You asked for an efficient solution, but efficiency is relative. This solution is efficient in terms of...
...memory because now new arrays are allocated (hush, we don't talk about all the enumerators created by this code);
...laziness, because only requested values will be computed;
...code size.
It's not the most efficient in terms of runtime speed, because of all the overhead enumerators introduce.

Finding Highest and Lowest value in Array and removing them to compute an average C#

I am trying to write code that finds the lowest and highest values stored in an array and then removes them from the array to compute an average.
Currently I have written code to produce the average of all numbers in the array but I need to change that once I figure out how to remove Highest and lowest value.
Code I have:
private void HighAndLow()
{
try
{
int[] HighAndLowGrade;
int[] highest = HighAndLowGrade.Max();
int lowest = HighAndLowGrade.Min();
}
catch
{
MessageBox.Show("HighAndLow Method failed");
}
}
//find average without highest and lowest values
private void ComputeMean()
{
double total = 0;
for (int index = 2; index < 9; index ++)
{
total += double.Parse(lineContent[index]);
}
averageTestScore = total / 7;
}
This should work from what I have tested so far.
int[] numberArray = new int[] {1,2,5,9,5,2};
double answer = 0;
var ignoreList = new List<decimal>() {
numberArray.Max(),
numberArray.Min()
};
var cleanList = numberArray.Where(x => !ignoreList.Contains(x));
answer = cleanList.Any() ? cleanList.Average() : 0;
This only requires one iteration through the collection:
public double ComputeAdjustedMean(IEnumerable<int> items)
{
int total = 0;
int count = 0;
int min = int.MaxValue;
int max = int.MinValue;
foreach(int item in items)
{
count++;
total += item;
if (item < min) min = item;
if (item > max) max = item;
}
if (count <= 2) // not enough items
{
// do something here
}
return (total - (min + max)) / (double)(count - 2);
}
Try this using bubble sorting algorithm-
static void Main(string[] args)
{
int[] array = { 12, 6, 34, 23, 89 };
int temp;
for (int i = 0; i <= array.Length - 2; i++)
{
if (array[i] > array[i + 1])
{
temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
array = array.Skip(1).SkipLast(1).ToArray();
Console.WriteLine((array.Sum()) / (array.Length));
Console.Read();
}
If you have an array of values then you can do this neat LINQ query:
var average_skip_min_and_max =
values
.OrderBy(x => x)
.Skip(1)
.Take(values.Length - 2)
.Average();
I really don't get people when they encounter this kind of questions, they became insanely eager to provide a direct answer. This question is obviously a homework assignment. I'm not saying we don't help OPs but we need to lead them to solutions.
Dear OP,
Do not use the LINQ, yet. I think your instructor is meaning you to learn the sorting algorithms and memory operations. Do some research about them, say, Buble Sort, to sort the array you have. Then it'll be in front of you how to implement and use. After then, you should use the framework provided methods like LINQ's Min() / Max() extension methods.
The approach to your problem is could be like this:
Sort the array ascending.
Get the first element which is now the minimum valued element.
Reallocate a new array but 1 element shorter
Copy your entire array with the current ordered state to newly allocated array but skip the first element when copying, start with next element.
Get the minimum again, but this time search in the newly allocated array and check with the previous minimum
If they are equal go the 3rd operation, if you need to eliminate the repeating minimums ( [1, 1, 2, 3 ...] ), which I think you need to.
If they are not equal, then it means you've found the minimum element of your array and removed all occurences
Now if you repeat the approach to finding the maximum valued element you are done with the elimination process.

Is it okay to exit a loop when an exception is thrown?

I solved a task on Hackerrank.com, where the problem was like this:
You have an Array. This Array contains numbers.
Now you enter two numbers:
The first one describes a sum
The second one describes the amount of indexes (sequence length) you add together
In the end you get the amount of sequences whose sum is your defined number
For example:
Your array is [ 1, 2, 3, 4], your sum is 3 and your sequence length is 2.
Now you take the first two indexes and output the sum: [1, 2] = 3.
This is equal to your sum, so now you have found one sequence.
The next sequence is [ 2, 3 ] = 5. This is not equal to 3, so your sequence counter stays 1.
The last sequence is [3, 4] = 7. This is also not equal to 3 and in the end, you found one sequence.
I wrote this code for that:
static int GetSequences(List<int> s, int d, int m)
{
//m = segment-length
//d = sum
int count = 0;
int j = 0;
int k = 0;
do
{
try
{
List<int> temp = new List<int>();
for (int i = 0; i < m; i++)
{
temp.Add(s[i + k]);
}
if (temp.Sum() == d)
{
count++;
}
j++;
k++;
}
catch (ArgumentOutOfRangeException)
{
break;
}
} while (true);
return count;
}
As I didn't know how often I have to count
(For example a 6-Length-Array with a sequence-length of 3 has 4 sequences (1,2,3 | 2,3,4 | 3,4,5 | 4,5,6)),
I am stopping the while loop when the index is out of range. but I'm not sure if this solution is okay. Not just with program speed, but also with code cleanliness. Is this code acceptable, or is it better to use a for loop, which loops for example exactly 4 times for a 6-length array with 3-Length sequences?
It's not recommended, no. Exceptions should be reserved for stuff that isn't supposed to happen, not flow control or validation.
What you want is to use conditional logic (if statements) and the break keyword.
Also, codereview.stackexchange.com is better suited for these kinds of questions.
It would be better to fix your code so that it doesn't routinely throw exceptions:
You sum each of these segments:
0 1 2 3 start = 0
| | summing indexes: 0, 1
+--+
0 1 2 3 start = 1
| | summing indexes: 1, 2
+--+
0 1 2 3 start = 2
| | summing indexes: 2, 3
+--+
The bracket starts at the index start, and has a size of m. The length of s is given by s.Count. Therefore we want to keep going until start + m == s.Count.
(I always find it's useful to draw these things out, and put sample numbers in, in order to make sure you've got the maths right. In the sample above, you can see that we stop when start (2) + m (2) == the array size (4))
static int GetSequences(List<int> s, int d, int m)
{
//m = segment-length
//d = sum
int count = 0;
for (int start = 0; start + m <= s.Count; start++)
{
List<int> temp = new List<int>();
for (int i = 0; i < m; i++)
{
temp.Add(s[start + i]);
}
if (temp.Sum() == d)
{
count++;
}
}
return count;
}
However, you can improve your code a bit:
Use meaningful variable names
Don't create a new temporary list each time, just to sum it
Check your inputs
static int GetSequences(List<int> numbers, int targetSum, int segmentLength)
{
if (numbers == null)
throw new ArgumentNullException(nameof(numbers));
if (segmentLength > numbers.Count)
throw new ArgumentException("segmentLength must be <= numbers.Count");
int count = 0;
for (int start = 0; start + segmentLength <= numbers.Count; start++)
{
int sum = 0;
for (int i = 0; i < segmentLength; i++)
{
sum += numbers[start + i];
}
if (sum == targetSum)
{
count++;
}
}
}
Usually except for switch/case there is often no real reason to use break.
Also an exception MUST be as the name says exceptional, so it MUST NOT be a part of your logic.
As said Jeppe you can use the methods and attributes the framework provides you to do as you like.
Here s.Count seems to be the way to go.
int[] arr = new[] { 1, 2, 1, 2 };
// Sum and len are given by the task.
// 'last' is the last index where we should stop iterating.
int sum = 3, len = 2, last = arr.Length - len;
// One of the overloads of Where accepts index, i.e. the position of element.
// 1) We check that we don't go after our stop-index (last).
// 2) Avoid exception by using '&&'.
// 3) We use C# 8 Range (..) to get the slice of the numbers we need:
// we start from the current position (index) till then index,
// calculated as current index + length given by the task.
// 4) Sum all the numbers in the slice (Sum()) and compare it with the target sum,
// given by the task (== sum).
// 5) The count of all matches (Count()) is the sought amount of sequences.
int count = arr.Where((z, index) => index <= last && arr[index..(index+len)].Sum() == sum).Count();

Formula to produce 1 for positive integers and 0 otherwise

I have a function (f) the takes a number of items (n) and a number of columns (c) and returns the optimal layout as an array of items per column. I define optimal as being as square as possible. So f(4,4) would return [4,4,4,4], f(17,4) would return [5,4,4,4], and f(1,4) would return [1,0,0,0]. My function works correctly in all my tests, but I am looking to alter it. My desire to do this is not because I am looking increase performance. I just want to do this, because I am experimenting and want to learn different techniques.
Here is the code:
public static int[] f(int n, int c){
int[] a = new int[c];
if(c>0 && n>=0){
int opt = (n-(n%c))/c;
n = n - (opt*c);
for(int i = 0;i<a.Length;i++){
a[i] = opt;
if(n>0){
a[i]++;
n--;
}
}
}
return a;
}
The function works by first determining the optimal number of items per col:
int opt = (n-(n%c))/c;
So f(17,4) would yield 4, f(19,4) would also yield 4, and f(3,4) would yield 0. Then the reminder is calculated:
n = n - (opt*c);
I then loop through the array (of length c) and assign a[i] equal to the optimal value. Finally, if the reminder is greater than 0 I add 1 to a[i]. This equally distributes the reminder across the array. This is the part I would like to alter.
Instead of checking if(n>0) and adding 1 to the array is there a formula I could use that might look like:
a[i] = opt + n*?????;
So n*??? would always equal 1 if n is greater than 0 and 0 if n is 0 or less?
The simple answer to your question is to use an expression with the conditional operator:
a[i] = opt + (n > 0 ? 1 : 0);
(n > 0 ? 1 : 0) will be 1 if n is greater than 0, and 0 otherwise.
On that note, there is a clearer and more concise way to implement your algorithm.
Determine the total number of items that can be distributed evenly between the slots (call this average). This has the value n / c (using integer division).
Determine the remainder that would be left after those are evenly distributed (call this remainder). This has the value n % c.
Put the value average + 1 in the first remainder slots, and put average in the rest.
The implementation for this would be:
public static int[] Distribute(int total, int buckets)
{
if (total < 0) { throw new ArgumentException("cannot be less than 0", "total"); }
if (buckets < 1) { throw new ArgumentException("cannot be less than 1", "buckets"); }
var average = total / buckets;
var remainder = total % buckets;
var array = new int[buckets];
for (var i = 0; i < buckets; i++)
{
array[i] = average + (i < remainder ? 1 : 0);
}
return array;
}
And the obligatory Linq version:
public static int[] DistributeLinq(int total, int buckets)
{
if (total < 0) { throw new ArgumentException("cannot be less than 0", "total"); }
if (buckets < 1) { throw new ArgumentException("cannot be less than 1", "buckets"); }
var average = total / buckets;
var remainder = total % buckets;
return Enumerable.Range(1, buckets)
.Select(v => average + (v <= remainder ? 1 : 0))
.ToArray();
}
If you want to use a formula:
Math.Max(n - Math.Abs(n - 1), 0)
should do the trick.
Your code should look like:
a[i] = opt + Math.Max(n - Math.Abs(n - 1), 0)
Another option for a formula would be
Math.Max(Math.Sign(n), 0)
If you are looking for a mathematical formula, I'm not sure you're going to find it as the function is discontinuous at n = 0.
How about a simple function which outputs int on a bool expression?
int IsPositive(int number)
{
//if number is > 0 return integer one (1), else return integer zero (0)
return number > 0 ? 1 : 0;
}
You can then use this in your code as such:
a[i] = opt + IsPositive(n);
//opt + 1 if n > 0, opt + 0 if n <= 0
Update: per your comment, you can just move the evaluation inline:
a[i] = opt + (n > 0 ? 1 : 0);
As an aside: you should make #BradleyDotNET's comment one of your programming mottos.

How to find minimum number of steps to sort an integer array

I have an integer array int[] number = { 3,4,2,5,1};
The minimum number of steps to sort it should be 2. But I am getting 4.
static void Main(string[] args)
{
int[] number = { 3,4,2,5,1};
int result = get_order(number);
Console.ReadKey();
}
public static int get_order(int[] input1)
{
input1 = input1.OrderByDescending(o => o).ToArray();
bool flag = true;
int temp;
int numLength = input1.Length;
int passes = 0;
for (int i = 1; (i <= (numLength - 1)) && flag; i++)
{
flag = false;
for (int j = 0; j < (numLength - 1); j++)
{
if (input1[j + 1] > input1[j])
{
temp = input1[j];
input1[j] = input1[j + 1];
input1[j + 1] = temp;
flag = true;
}
}
passes++;
}
return passes+1;
}
What is the problem and what changes i need to do in my code?
Edit
implement #Patashu, algorithm,
public static int get_order(int[] input1)
{
var sorterArray = input1.OrderByDescending(o => o).ToArray();
var unsortedArray = input1;
int temp1;
int swap = 0;
int arrayLength = sorterArray.Length;
for (int i = 0; i < arrayLength; i++)
{
if (sorterArray[i] != unsortedArray[i])
{
temp1 = unsortedArray[i];
unsortedArray[i] = sorterArray[i];
for (int j = i + 1; j < arrayLength; j++)
{
if (unsortedArray[j] == sorterArray[i])
{
unsortedArray[j] = temp1;
swap++;
break;
}
}
}
}
return swap;
}
The problem with your algorithm is that it only attempts swapping adjacent elements.
3,4,2,5,1 is best sorted by swapping 3 with 5, which is an unadjacent swap, and then 2 with 3.
So, I suggest that you will find a better algorithm by doing the following:
1) First, sort the array into descending order using the built in sorting function of C#.
2) Now, you can use this sorted array as a comparison - iterate through the array from left to right. Every time you see an element in the unsorted array that is != to the element in the same space in the sorted array, look deeper into the unsorted array for the value the sorted array has there, and do one swap.
e.g.
3,4,2,5,1
Sort using Sort -> 5,4,3,2,1 is our sorted array
3 is != 5 - look in unsorted array for 5 - found it, swap them.
Unsorted is now 5,4,2,3,1
4 == 4
2 is != 3 - look in unsorted array for 3 - found it, swap them.
Unsorted is now 5,4,3,2,1
2 == 2
1 == 1
We're at the end of the unsorted array and we did two swaps.
EDIT: In your algorithm implementation, it looks almost right except
instead of
unsortedArray[j] = sorterArray[i];
unsortedArray[i] = temp1;
you had it backwards, you want
unsortedArray[j] = temp1;
unsortedArray[i] = sorterArray[i];
Since you're asking why you're getting 4 steps, and not how to calculate the passes, the correct way to do this is to simply step through your code. In your case the code is simple enough to step through on a piece of paper, in the debugger, or with added debug statements.
Original: 3, 4, 2, 5, 1
Pass: 1: 4, 3, 5, 2, 1
Pass: 2: 4, 5, 3, 2, 1
Pass: 3: 5, 4, 3, 2, 1
Pass: 4: 5, 4, 3, 2, 1
Basically what you see is that each iteration you sort one number into the correct position. At the end of pass one 2 is in the correct position. Then 3, 4, 5.
Ah! But this is only 3 passes you say. But you're actually incrementing passes regardless of flag, which shows you that you actually did one extra step where the array is sorted (in reverse order) but you didn't know this so you had to go through and double check (this was pass 4).
To improve performance, you do not need to start checking the array from the beginning.
Better than the last equal element.
static int MinimumSwaps(int[] arr)
{
int result = 0;
int temp;
int counter = 0;
for (int i = 0; i < arr.Length; ++i)
{
if (arr[i] - 1 == i)
{
//once all sorted then
if(counter==arr.Length)break;
counter++;
continue;
}
temp = arr[arr[i]-1];
arr[arr[i] - 1] = arr[i];
arr[i] = temp;
result++;//swapped
i = counter ;//needs to start from the last equal element
}
return result;
}
At the start:
{ 3,4,2,5,1}; // passes = 0
Round 1 reuslt:
{ 4,3,2,5,1};
{ 4,3,5,2,1}; // passes = 1
Round 2 reuslt:
{ 4,5,3,2,1}; // passes = 2
Round 3 reuslt:
{ 5,4,3,2,1}; // passes = 3 and flag is set to true
Round 4 reuslt:
{ 5,4,3,2,1}; // same result and passes is incremented to be 4
You fail to mention that the array is supposed to be sorted in descending order, which is usually not the default expected behavior (at least in "C" / C++). To turn:
3, 4, 2, 5, 1
into:
1, 2, 3, 4, 5
one indeed needs 4 (non-adjacent) swaps. However, to turn it into:
5, 4, 3, 2, 1
only two swaps suffice. The following algorithm finds the number of swaps in O(m) of swap operations where m is number of swaps, which is always strictly less than the number of items in the array, n (alternately the complexity is O(m + n) of loop iterations):
int n = 5;
size_t P[] = {3, 4, 2, 5, 1};
for(int i = 0; i < n; ++ i)
-- P[i];
// need zero-based indices (yours are 1-based)
for(int i = 0; i < n; ++ i)
P[i] = 4 - P[i];
// reverse order?
size_t count = 0;
for(int i = 0; i < n; ++ i) {
for(; P[i] != i; ++ count) // could be permuted multiple times
std::swap(P[P[i]], P[i]); // look where the number at hand should be
}
// count number of permutations
This indeed finds two swaps. Note that the permutation is destroyed in the process.
The test case for this algorithm can be found here (tested with Visual Studio 2008).
Here is the solution for your question :)
static int MinimumSwaps(int[] arr)
{
int result = 0;
int temp;
int counter = 0;
for (int i = 0; i < arr.Length; ++i)
{
if (arr[i] - 1 == i)
{
//once all sorted then
if(counter==arr.Length)break;
counter++;
continue;
}
temp = arr[arr[i]-1];
arr[arr[i] - 1] = arr[i];
arr[i] = temp;
result++;//swapped
i = 0;//needs to start from the beginning after every swap
counter = 0;//clearing the sorted array counter
}
return result;
}

Categories

Resources