I've been having trouble trying to get the proper index of list(I). Basically the algorithm sorts through a list of consecutive numbers such as 1,3,5,7,9,13 and returns which number is missing (11 in this case). My problem is that temp stays at -1, any idea on why? From my understanding, temp should increase as i gets incremented
public static int FindMissing(List<int> list)
{
int difference;
int missing = 0;
for (int i = 0; i < list.Count; i++)
{
difference = list[1] - list[0];
int temp = list.IndexOf(i);
if (temp > 0)
{
if (list[i] - list[i - 1] != difference)
{
missing = list[i - 1] + difference;
}
}
}
return missing;
}
Alexandru Popa gave me a good answer, but for future people looking at this thread, someone showed me the continue keyword which ended up working like this
public static int FindMissing(List<int> list)
{
int difference;
int missing = 0;
for (int i = 0; i < list.Count; i++)
{
if (i == 0) continue;
difference = list[1] - list[0];
if (list[i] - list[i - 1] != difference)
{
missing = list[i - 1] + difference;
}
}
return missing;
}
We need to make some changes in your code.
First, let's check if the list contains at least two elements, otherwise we shouldn't run the algorithm.
if(list.Count <= 2)
return 0;
Second, move the declaration and initialization of difference out of the loop. As difference is constant, you shouldn't calculate it on each iteration.
if(list.Count <= 2)
return 0;
int difference = list[1] - list[0];
Third, let's start the loop from index 2 as there's no need to check if difference equals difference.
if(list.Count <= 2)
return 0;
int difference = list[1] - list[0];
for (int i = 2; i < list.Count; i++)
{
}
Fourth, there is no need to check if your list contains its index, that's the sketchy part of your code, you only need to look at the differences between each neighbors. When one of them doesn't match up your initial difference you got your missing number. And we should return immediately, otherwise it can be overwritten if there are other missing elements in your list.
public static int FindMissing(List<int> list)
{
if(list.Count <= 2)
return 0;
int difference = list[1] - list[0];
for (int i = 2; i < list.Count; i++)
{
if (list[i] - list[i - 1] != difference)
{
return list[i - 1] + difference;
}
}
return 0;
}
However this algorithm does not check for the integrity of the list. It only finds the first missing element in your list. It does not tell us whether the list contains other missing elements or not.
According to the comment in your question - you said that your list consist of elements: 1040,1220,1580.
Now in the for loop your index (i) will have the values 0,1,2.
Then your temp value will try to find the IndexOf the values of i - 0,1,2.
But in your list, there are no such values. Your values are 1040,1220,1580. So the IndexOf will always return -1.
This is why you always see -1.
Clear up a bit your question and code.
Related
I'm trying to make a scan of an array where it follows the index with the numbers inside and I don't understand why it gives me this exception. I cant add any more details its a pretty straight forward question.
using System;
public class Program
{
public static bool IsPerfect(int[] arr)
{
int next=0, done=0,i;
while (done == 0)
{
i = arr[next];
arr[next] = 10;
next = arr[i];
if (i == 0)
done = 1;
}
for(int j = 0; j < arr.Length; j++)
if (arr[j] != 10)
return false;
return true;
}
public static void Main()
{
int[] arr = { 3, 0, 1, 4, 2 };
if (IsPerfect(arr) == true)
Console.WriteLine("is perfect");
if (IsPerfect(arr) == false)
Console.WriteLine("boooo");
}
}
You are not specifying the functioning for duplicates... Use a method to check for duplicates and as soon as you encounter a duplicate element exit the loop... It will work fine! đź‘Ť
ok for anyone intrested the problem was lying in the second if, and the "next = arr[i];" the first i changed because it made more sense and the second and main problem was the other if. because i had the second condition it ran the method twice and with the changed values it returned an error.
the solution was to put else instead.
Reverse engineering: we mark visited items and if all items are visted, then we have a "Perfect" array.
Problem: we mark item with 10 which can be an index (what if array has, say, 15 items)?
Solution: let's mark by -1 (definitely not an index - an array can have negative number of items) and check if item has been marked:
Tricky moment: we should assign -1 to the current arr[i] item but use its initial value to be assigned to i. Sure, we can save i and put it as
for (int i = 0; i >= 0 && i < arr.Length; ) {
int nextI = arr[i];
arr[i] = i;
i = nextI;
}
but let's put in a short modern way: (i, arr[i]) = (arr[i], -1);
Code:
public static bool IsPerfect(int[] arr) {
// In public method we must be ready for any input; null included
if (arr == null)
return false; // or throw new ArgumentNullException(nameof(arr));
// Do we have a valid array?
for (int i = 0; i < arr.Length; ++i)
if (arr[i] < 0 || arr[i] >= arr.Length)
return false;
// Note the condition: we read the next item - arr[i] -
// if and only if i is within range
// Note, that we have nothing to increment / decrement
for (int i = 0; i >= 0 && i < arr.Length; )
(i, arr[i]) = (arr[i], -1); // note the assignment: both i and arr[i] in one go
// We have marked all that we could.
// Do we have unmarked items?
for (int i = 0; i < arr.Length; ++i)
if (arr[i] != -1) // ... yes, we have and thus
return false; // arr is not perfect
return true;
}
Please, fiddle
So I'm just trying to understand how bubblesort (it may help me with other algorithms when I see this kind of stuff as well) works with the nested for loop.
I noticed that most people will do the loops like so:
public static void BubbleSort(int[] arr, int arr_size)
{
int i, j, temp;
bool swapped;
for (i = 0; i < arr_size - 1; i++)
{
swapped = false;
for (j = 0; j < arr_size - i -1; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (swapped == false)
{
break;
}
}
}
I have done it like this (only slightly different; note the nested loop size check:
public static void BubbleSort(int[] arr, int arr_size)
{
int i, j, temp;
bool swapped;
for (i = 0; i < arr_size - 1; i++)
{
swapped = false;
for (j = 0; j < arr_size - 1; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (swapped == false)
{
break;
}
}
}
And it seems to work with every check I've done so far.
I guess to sum it up, I am wondering why the first loop would be the size - 1 (I know this is because of the whitespace at the end) and the nested loop will be the size - i - 1 (at least I have seen this a lot). Thanks for any feedback !
The effect of the inner loop:
for (j = 0; j < arr_size - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
is finding the maximum element in the array and placing it to the last position. Hence, for i == 0 (the index from the outer loop), it moves it to the last array position. For i == 1, the array's overall maximum element is already at the last array position, and hence it does not need to be processed again. For i == 2 etc. the situation is the same. In other words, the array is being sorted from 'backward' by 'bubbling' (hence the algorithm's name) the maximum elements up each iteration.
There is a nice step-by-step example on Wikipedia.
In your second example, by omitting the - i in the for loop clause, you are just unnecessarily checking array elements that are already in place from previous (outer loop) iterations and hence cannot change anymore.
I am trying to make a bubble sort program that can sort array of integers from bottom.
var list = new int[] {5,0,2}; //array
for (int i = 0; i < list.Length; i++)
{
while (list[i] > list[i+1])
{
list[i] = list[i + 1];
}
}
Console.WriteLine(string.Join(",", list));
I get the index out of range error in the while (list[i] > list[i+1]). What is wrong with my code? Is my while condition bad?
is my while condition bad?
No, your for loop condition is incorrect. Look at the loop here and consider what that says about the value of i within the body of the loop.
for (int i = 0; i < list.Length; i++)
That ensures that list[i] is always valid. But you're using list[i + 1], so you need to make sure that i + 1 is a valid index into the array. The simplest way to do that is to just reduce the limit in the condition:
for (int i = 0; i < list.Length - 1; i++)
That will remove the exception, but you'll be left with this while loop:
while (list[i] > list[i+1])
{
list[i] = list[i + 1];
}
You don't modify the value of i within the loop, which means it's only ever going to execute once - as soon as you've executed the body of that loop, the condition will become false. So it would be clearer to write it as an if statement:
if (list[i] > list[i+1])
{
list[i] = list[i + 1];
}
Now I suspect that's not really what you want - you probably want to swap values rather than just assigning, and you probably want a single loop, but that's rather beyond the scope of the immediate question.
Thx everyone for help, finally i made it work with adding a bool that guarantees checking the array if it is needed to repeat inner loop again:
var list = new int[] {5,7,0,2}; //array
bool alert = true;
while (alert == true)
{
alert = false;
for (int i = 0; i < list.Length - 1; i++)
{
while (list[i] > list[i + 1])
{
int temp = list[i];
list[i] = list[i + 1];
list[i + 1] = temp;
alert = true;
}
}
}
Console.WriteLine(string.Join(",", list));
Console.ReadKey();
given a binary number find the maximum consecutive 1s or 0s that can be obtained by flipping only one bit (either a 1 or a 0)
the code given was
public int getMacCon(string[] A)
{
int n = A.Length;
int result = 0;
for (int i = 0; i < n - 1; i++)
{
if (A[i] == A[i + 1])
result = result + 1;
}
int r = -2;
for (int i = 0; i < n; i++)
{
int count = 0;
if (i > 0)
{
if (A[i - 1] != A[i])
count = count + 1;
else
count = count - 1;
}
if (i < n - 1)
{
if (A[i + 1] != A[i])
count = count + 1;
else
count = count - 1;
}
r = Math.Max(r, count);
}
return result + r;
}
Im finding hard to figure out the logic here. specially the given below part
for (int i = 0; i < n - 1; i++)
{
if (A[i] == A[i + 1])
result = result + 1;
}
I would highly apretiate if any one can explain me the logic in this solution.
Thanks
The bit you've highlighted just counts the number of currently adjacent equal values, i.e. where one value (A[i]) is equal to the next (A[i+1]). It then asks (the second loop), for each value in turn, whether flipping it would increase vs decrease vs not change the number of adjacent equal values; so if a value is currently different from the one before it (A[i-1] != A[i]), a flip would be an increase - else decrease; likewise the one after it. The final result is the pre-existing number of adjacent equal values (result), plus the best delta (r) found in the sweep.
public int getMacCon(string[] A)
{
int n = A.Length;
int result = 0;
// find how many adjacent values are currently in the string
for (int i = 0; i < n - 1; i++)
{
// if same as the next value, that's a hit
if (A[i] == A[i + 1])
result = result + 1;
}
// worst case delta from flipping one value is that me make it
// worse on both sides, so -2
int r = -2;
// now consider each value in turn
for (int i = 0; i < n; i++)
{
int count = 0;
if (i > 0) // test value before, if not the first value
{
if (A[i - 1] != A[i])
count = count + 1; // before is different; flip is incr
else
count = count - 1; // before is same; flip is decr
}
if (i < n - 1) // test value after, if not the last value
{
if (A[i + 1] != A[i])
count = count + 1; // after is different; flip is incr
else
count = count - 1; // after is same; flip is decr
}
// compare that to the tracking counter, and keep the best value
r = Math.Max(r, count);
}
// final result is sum of pre-existing count plus the delta
return result + r;
}
Incidentally, an optimization might be to change the second loop test from i < n to i < n && r != 2 - i.e. stop as soon as the best possible delta is found (making it better on both sides, +2)
Not an direct answer to your question (as Marc Gravell's answer covers it enough) but I just need to add how would I solve this instead:
encode your string with RLE (run length encoding)
so you need array of b,v,n values. Where b>=0 is start position, v={0,1} is bit value and n is the count of consequent occurencies. For example something like:
const int _max=100; // max number of bits
int b[_max],v[_max],n[_max],bvns=0;
The bvns is number of used b,v,n in the arrays. You can also use any dynamic list/template instead.
reset your actual solution
You need bit position to change ix and the count of consequent bits resulting after its flip sz. Set booth to zero.
scan the RLE for items with n=1
if found that means item before and after in the RLE is the same so flipping will join them. So compute the resulting size and if bigger then store as actual solution something like:
for (int i=1;i<bvns-1;i++) // scann RLE except first and last item
if (n[i]==1) // single bit found
{
l=n[i-1]+1+n[i+1]; // resulting size
if (l>=sz) { sz=l; ix=b; } // update solution
}
test if enlarging single sequence is not bigger
simply:
for (int i=0;i<bvns;i++) // scann RLE
if (n[i]>=sz) // result is bigger?
{
sz=l; ix=b-1; // update solution
if (ix<0) ix=b+n[i];
}
I have a list of integer arrays, and i want to check for each array if the array if chronological, if it is not I want it to be removed from the list.
At the moment I do it like this:
for (int i = 0; i < allXcombis.Count(); i++)
{
bool remove = false;
for (int j = 0; j < allXcombis[i].Length; j++)
{
if (allXcombis[i].Count() - 1 > j)
if (allXcombis[i][j] != allXcombis[i][j + 1] - 1)
remove = true;
}
if (remove)
allXcombis.Remove(allXcombis[i]);
}
but I am not really happy with this code, I think it can be done easier.
First, I would probably extract the checking that the array is “chronological” into its own method and made it more efficient, by returning from the loop early:
bool IsChronological(int[] array)
{
for (int i = 0; i < array.Length - 1; i++)
{
if (array[i] != array[i + 1] - 1)
return false;
}
return true;
}
And then I would simply use RemoveAll():
allXcombis.RemoveAll(a => !IsChronological(a));
This way, you get concise, readable code and you don't have to worry about indexes in the list (as others mentioned, you have a bug in your code, because you're not careful about the indexes).
When you are removing from list inside loop, you need either to fix loop variable or to loop backwards. Then, you don't need () after Count. And you can break from loop after assigning remove = true, this will improve performance.
for (int i = allXcombis.Count - 1; i >= 0; i--)
{
bool remove = false;
for (int j = 0; j < allXcombis[i].Length; j++)
{
if (allXcombis[i].Length - 1 > j)
{
if (allXcombis[i][j] != allXcombis[i][j + 1] - 1)
{
remove = true;
break;
}
}
}
if (remove)
allXcombis.Remove(allXcombis[i]);
}
If by chronological you mean sorted, then you need to check < not !=.
Also you can simplify some things. The most important is when you find that it's not sorted to break out of the inner loop, so that you don't keep iterating.
Also you need to decrease i when you remove, because you'll skip some arrays otherwise (say if i = 2 and you remove the second array, then the third array becomes second, but i will be 3 on the next iteration, so you'll skip it)
for (int i = 0; i < allXcombis.Count; i++)
{
for (int j = 0; j < allXcombis[i].Length-1; j++)
{
if (allXcombis[i][j] > allXcombis[i][j + 1] - 1)
{
allXcombis.Remove(allXcombis[i]);
i--;
break;
}
}
}
I agree with svick in the use of a dedicated method like he proposed "IsChronological" but I would like to add a little bit of security and performance to this method:
bool IsChronological(int[] array)
{
bool result = ((array == null) || (array.Length == 0)) ? false : true; //Null or empty arrays are not chronological by definition (also avoid exceptions)
if (result)
{
result = (array.Length == 1) ? true : false; //Arrays with only one element are chronological by definition
if (!result)
{
int length = array.Length - 1;
int index = 0;
while ((index < length) && (array[index] == array[index] + 1))
index++;
result = (index == array.length);
}
}
return result;
}