Having trouble understanding a solution to this c# algorithm - c#

I was doing a LeetCode exercise for c# and made my own solution for the following prompt:
"Given a binary array nums, return the maximum number of consecutive 1's in the array."
"Input: nums = [1,1,0,1,1,1]
Output: 3
Explanation: The first two digits or the last three digits are consecutive 1s. The maximum number of consecutive 1s is 3."
My solution had a hardcoded array value, and i found a solution online that worked and ran fine. However, im having a really hard time understanding what the isStart and isEnd bools do. The code is below:
public class Solution {
public int FindMaxConsecutiveOnes(int[] nums)
{
if(nums == null || nums.Length == 0)
{
return 0;
}
var start = 0;
var length = nums.Length;
var maxLength = 0;
for(int i = 0; i < length; i++)
{
var current = nums[i];
bool isStart = current == 1 && (i == 0 || nums[i - 1] == 0);
bool isEnd = current == 1 && (i == length - 1 || nums[i + 1] == 0);
if (isStart)
{
start = i;
}
if(isEnd)
{
var currentOnes = i - start + 1;
maxLength = currentOnes > maxLength ? currentOnes : maxLength;
}
}
return maxLength;
}
I assume isStart and isEnd determine if we are at the Start or End of the array? I dont really understand what the operators do either. Any help could be appreciated. Thanks :)

Related

Move an element from an array

How can I move an element from an index, for example to the front. Let's say this example : moving the second index to the front, and the rest of the elements remain the same. As I am working with algorithms I can't implement things like lists that I found most efficient I guess.
Example : 1 2 3 4
Output : 3 1 2 4
I assigned the value from the index to a temporary variable so far. But I do not know how to shift the elements, I'm guessing implementing somehow a for loop.
You have to change how you iterate based on whether your desired index is before or after the elements original index and handle those cases individually.
public static void MoveToIndex(int[] array, int from, int to)
{
if (array.Length < 2) return;
if (from == to) return;
if (from < 0 || array.Length <= from) throw new ArgumentException(nameof(from));
if (to < 0 || array.Length <= to) throw new ArgumentException(nameof(to));
var startIndex = Math.Min(from, to);
var endIndex = Math.Max(from, to);
var swappedValue = array[startIndex];
if (to < from)
{
array[startIndex] = array[endIndex];
}
for (var i = startIndex + 1; i <= endIndex; i++)
{
var current = array[i];
if (to < from)
{
array[i] = swappedValue;
swappedValue = current;
}
else
{
array[i - 1] = i == endIndex ? swappedValue : current;
}
}
}

Calculate 2^(n) where 0<n<10000

So, this is my problem to solve:
I want to calculate 2^(n) where 0 < n< 10000
I am representing each element of array as a space where 4digit number should be "living" and if extra digit appears, I am replacing it to the next element of this array.
The principle I am using looks like this:
The code I am using is the following:
static string NotEfficient(int power)
{
if (power < 0)
throw new Exception("Power shouldn't be negative");
if (power == 0)
return "1";
if (power == 1)
return "2";
int[] A = new int[3750];
int current4Digit = 0;
//at first 2 is written in first element of array
A[current4Digit] = 2;
int currentPower = 1;
while (currentPower < power)
{
//multiply every 4digit by 2
for (int i = 0; i <= current4Digit; i++)
{
A[i] *= 2;
}
currentPower++;
//checking every 4digit if it
//contains 5 digit and if yes remove and
//put it in next 4digit
for (int i = 0; i <= current4Digit; i++)
{
if (A[i] / 10000 > 0)
{
int more = A[i] / 10000;
A[i] = A[i] % 10000;
A[i + 1] += more;
//if new digit should be opened
if (i + 1 > current4Digit)
{
current4Digit++;
}
}
}
}
//getting data from array to generate answer
string answer = "";
for (int i = current4Digit; i >= 0; i--)
{
answer += A[i].ToString() + ",";
}
return answer;
}
The problem I have is that it doesn't display correctly the number, which contains 0 in reality. for example 2 ^ (50) = 1 125 899 906 842 624 and with my algorithm I get 1 125 899 96 842 624 (0 is missing). This isn't only for 50...
This happens when I have the following situation for example:
How I can make this algorithm better?
Use BigInteger, which is already included in .Net Core or available in the System.Runtime.Numerics Nuget Package.
static string Efficient(int power)
{
var result = BigInteger.Pow(2, power);
return result.ToString(CultureInfo.InvariantCulture);
}
On my machine, NotEfficient takes roughly 80ms, where Efficient takes 0.3ms. You should be able to manipulate that string (if I'm understanding your problem statement correctly):
static string InsertCommas(string value)
{
var sb = new StringBuilder(value);
for (var i = value.Length - 4; i > 0; i -= 4)
{
sb.Insert(i, ',');
}
return sb.ToString();
}
One way to resolve this is to pad your 4-digit numbers with leading zeroes if they are less than four digits by using the PadLeft method:
answer += A[i].ToString().PadLeft(4, '0') + ",";
And then you can use the TrimStart method to remove any leading zeros from the final result:
return answer.TrimStart('0');

Sorting array numbers in c#

I have an assingment and I'm a bit lost. In an array of 10 (or less) numbers which the user enters (I have this part done), I need to find the second smallest number. My friend sent me this code, but I'm having a hard time understanding it and writing it in c#:
Solved it!!! :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int vnesena;
int? min1 = null;
int? min2 = null;
for(int i=1; i<11; i=i+1)
{
Console.WriteLine("Vpiši " + i +"." + " število: ");
vnesena = Convert.ToInt32(Console.ReadLine());
if (vnesena == 0)
{
break;
}
if (min1 == null || vnesena < min1)
{
min2 = min1;
min1 = vnesena;
}
else if (vnesena != min1 && (min2==null || vnesena<min2))
{
min2 = vnesena;
}
}
if (min1 == null || min2 == null)
{
Console.WriteLine("Opozorilo o napaki");
}
else
{
Console.WriteLine("Izhod: " + min2);
}
Console.ReadKey();
}
}
}
That code is too complicated, so try something like this.
int[] numbers = new int[10];
for (int i = 0; i < 10; i++)
{
numbers[i] = int.Parse(Console.ReadLine());
}
Array.Sort(numbers);
Console.WriteLine("Second smallest number: " + numbers[1]);
If the code isn't too obvious, let me explain:
Declare an array of 10 integers
Loop 10 ten times and each time, ask for user input & place input as an integer to the array
Sort the array so each number is in the number order (smallest first, biggest last).
The first integer is smallest (input at index 0, so numbers[0]) and the second smallest is obviously numbers[1].
Of course, for this piece of code to work, you have to use this code in console program.
As you didn't mention if you are allowed to use built in sorting functions etc, I assume that Array.Sort() is valid.
EDIT: You updated your topic so I'll change my code to match criterias.
int[] numbers = new int[10];
bool tooShortInput = false;
for (int i = 0; i < 10; i++)
{
int input = int.Parse(Console.ReadLine());
if (input != 0)
{
numbers[i] = input;
}
else
{
if (i == 2)
{
Console.WriteLine("You only entered two numbers!");
tooShortInput = true;
break;
}
else
{
for (int j = 0; j < 10; j++)
{
if (numbers[j] == 0)
{
numbers[j] = 2147483647;
}
}
break;
}
}
}
// Sort the array
int temp = 0;
for (int write = 0; write < numbers.Length; write++) {
for (int sort = 0; sort < numbers.Length - 1; sort++) {
if (numbers[sort] > numbers[sort + 1]) {
temp = numbers[sort + 1];
numbers[sort + 1] = numbers[sort];
numbers[sort] = temp;
}
}
}
if (!tooShortInput)
{
Console.WriteLine("Second smallest number: " + numbers[1]);
}
If you don't understand the updated code, let me know, I will explain.
NOTE: This is fastly coded and tested with android phone so obviously this code isn't 5 star quality, not even close, but it qualifies :-).
Regards, TuukkaX.
To paraphrase the code given:
Set 2 variables to nothing. (This is so that there can be checks done later. int? could be used if you want to use null for one idea here.
Start loop through values.
Get next value.
If the minimum isn't set or the new value is lower than the minimum, replace the second lowest with the former lowest and lowest with the new value that was entered.
Otherwise, check if the new value isn't the same as the minimum and if the minimum isn't set or the entered value is lower than the second lowest then replace the second lowest with this new value.
Once the loop is done, if either minimum value isn't filled in then output there isn't such a value otherwise output the second lowest value.
Imagine if you had to do this manually. You'd likely keep track of the lowest value and second lowest value as you went through the array and the program is merely automating this process. What is the problem?
This is a rough translation of what your friend gave you that isn't that hard to translate to my mind.
int enteredValue;
int? smallest = null, secondSmallest = null;
for (int i = 0; i < 10; i = i + 1)
{
Console.WriteLine("Vpiši " + i+1 + " število: ");
enteredValue = Convert.ToInt32(Console.ReadLine());
if (smallest==null || enteredValue<smallest) {
secondSmallest=smallest;
smallest = enteredValue;
} else if (enteredValue!=smallest && enteredValue<secondSmallest) {
secondSmallest= enteredValue;
}
}
Why use a loop and not take advantage of the Array.Sort method?
int[] numbers = new int[4] { 4, 2, 6, 8 };
Array.Sort(numbers);
int secondSmallestNumber = numbers[1];

IPv6 Abbreviation(zero blocks compression) logic. I'm using c#

This is a complete un compressed IP address 2001:0008:0000:CD30:0000:0000:0000:0101
I need to compress it like this
2001:8:0:CD30::101
But i was only able to compress the zeroes in blocks like this
2001:8:0:CD30:0:0:0:101
using this code
string output = "";
string a = textBox1.Text;
if (a.Length != 39 )
MessageBox.Show("Invalid IP please enter the IPv6 IP in this format 6cd9:a87a:ad46:0005:ad40:0000:5698:8ab8");
else
{
for (int i = 0; i < a.Length; i++)
{
if ((a[i] >= '1' && a[i] <= '9') || (Char.ToLower(a[i]) >= 'a' && Char.ToLower(a[i]) <= 'f') || ((i + 1) % 5 == 0 && a[i] == ':'))
{
output = output + a[i];
}
else if ((a[i]=='0' && a[i-1]==':') || (a[i]=='0' && a[i-1]=='0' && a[i-2]==':') || (a[i]=='0' && a[i-1]=='0' && a[i-2]=='0' && a[i-3]==':'))
{
}
else if (a[i] == '0')
{
output = output + a[i];
}
else
{
MessageBox.Show("Invalid IP please enter the IPv6 IP in this format 6cd9:a87a:ad46:0005:ad40:0000:5698:8ab8");
}
}
textBox2.Text = output;
}
Im using c# but i only need the programming logic about how can whole blocks of zeroes be deleted the problem is there could be more then 1 group of blocks containing all zeros in an ip but only one should be abbreviated.
Was far more tricky than I expected, but here you got the way to do it with regular expressions:
private static string Compress(string ip)
{
var removedExtraZeros = ip.Replace("0000","*");
//2001:0008:*:CD30:*:*:*:0101
var blocks = ip.Split(':');
var regex = new Regex(":0+");
removedExtraZeros = regex.Replace(removedExtraZeros, ":");
//2001:8:*:CD30:*:*:*:101
var regex2 = new Regex(":\\*:\\*(:\\*)+:");
removedExtraZeros = regex2.Replace(removedExtraZeros, "::");
//2001:8:*:CD30::101
return removedExtraZeros.Replace("*", "0");
}
If you would like to achieve the same result without using Regex:
public string Compress(string value)
{
var values = value.Split(",");
var ints = values.Select(i => int.Parse(i, System.Globalization.NumberStyles.HexNumber));
var result = ints.Select(Conversion.Hex);
return string.Join(":", result);
}
Didn't spend time on micro-optimizations (stackalloc, spans, etc.) but this gives an idea. For reference on optimization, you can look at the implementation of the IPAddress.Parse in the .net core. Do mind that result of the IPAddress.Parse will give a different result than the example above:
Compress -> 2001:8:0:CD30:0:0:0:101
IPAddress.Parse -> 2001:8:0:cd30::101
This could be "cleaned" up by moving into some object and other ideas.
Edit:
After chatting with one of my colleagues, I spent some time writing an "optimized" version of this. I haven't spent time cleaning up the code, so maybe one of the future edits will be even cleaner.
public string Compress(string value)
{
Span<char> chars = stackalloc char[value.Length];
const char zero = '0';
const char colon = ':';
int index = 0;
int positionInSegment = 0;
bool startsWithZero;
while (index < _originalValue.Length)
{
startsWithZero = value[index] == zero && positionInSegment == 0;
positionInSegment++;
if (startsWithZero)
{
if (index == value.Length - 1)
{
chars[index] = zero;
break;
}
if (value[index + 1] == colon)
{
chars[index] = zero;
positionInSegment = 0;
index++;
continue;
}
positionInSegment = 0;
index++;
continue;
}
if (value[index] == colon)
{
positionInSegment = 0;
chars[index] = colon;
index++;
continue;
}
chars[index] = value[index];
index++;
}
return chars.ToString();
}
I have also created a public gist for future references:
https://gist.github.com/DeanMilojevic/7b4f1d060ce8cfa191592694b11234d7

An algorithm for a number divisible to n

At first user gives a number (n) to program, for example 5.
the program must find the smallest number that can be divided to n (5).
and this number can only consist of digits 0 and 9 not any other digits.
for example if user gives 5 to program.
numbers that can be divided to 5 are:
5, 10, 15, 20, 25, 30, ..., 85, 90, 95, ...
but 90 here is the smallest number that can be divided to 5 and also consist of digits (0 , 9). so answer for 5 must be 90.
and answer for 9 is 9, because it can be divided to 9 and consist of digit (9).
my code
string a = txtNumber.Text;
Int64 x = Convert.ToInt64(a);
Int64 i ,j=1,y=x;
bool t = false;
for (i = x + 1; t == false; i++)
{
if (i % 9 == 0 && i % 10 == 0 && i % x == 0)
{
j = i;
for (; (i /= 10) != 0; )
{
i /= 10;
if (i == 0)
t = true;
continue;
}
}
}
lblAnswer.Text = Convert.ToString(j);
If you're happy to go purely functional then this works:
Func<IEnumerable<long>> generate = () =>
{
Func<long, IEnumerable<long>> extend =
x => new [] { x * 10, x * 10 + 9 };
Func<IEnumerable<long>, IEnumerable<long>> generate2 = null;
generate2 = ns =>
{
var clean = ns.Where(n => n > 0).ToArray();
return clean.Any()
? clean.Concat(generate2(clean.SelectMany(extend)))
: Enumerable.Empty<long>();
};
return generate2(new[] { 9L, });
};
Func<long, long?> f = n =>
generate()
.Where(x => x % n == 0L)
.Cast<long?>()
.FirstOrDefault();
So rather than iterate through all possible values and test for 0 & 9 and divisibility, this just generates only numbers with 0 & 9 and then only tests for visibility. It is much faster this way.
I can call it like this:
var result = f(5L); // 90L
result = f(23L); //990909L
result = f(123L); //99999L
result = f(12321L); //90900999009L
result = f(123212L); //99909990090000900L
result = f(117238L); //990990990099990990L
result = f(1172438L); //null == No answer
These results are super fast. f(117238L) returns a result on my computer in 138ms.
You can try this way :
string a = txtNumber.Text;
Int64 x = Convert.ToInt64(a);
int counter;
for (counter = 1; !isValid(x * counter); counter++)
{
}
lblAnswer.Text = Convert.ToString(counter*x);
code above works by searching multiple of x incrementally until result that satisfy criteria : "consist of only 0 and or 9 digits" found. By searching only multiple of x, it is guaranteed to be divisible by x. So the rest is checking validity of result candidate, in this case using following isValid() function :
private static bool isValid(int number)
{
var lastDigit = number%10;
//last digit is invalid, return false
if (lastDigit != 0 & lastDigit != 9) return false;
//last digit is valid, but there is other digit(s)
if(number/10 >= 1)
{
//check validity of digit(s) before the last
return isValid(number/10);
}
//last digit is valid, and there is no other digit. return true
return true;
}
About strange empty for loop in snippet above, it is just syntactic sugar, to make the code a bit shorter. It is equal to following while loop :
counter = 1;
while(!isValid(input*counter))
{
counter++;
}
Use this simple code
int inputNumber = 5/*Or every other number, you can get this number from input.*/;
int result=1;
for (int i = 1; !IsOk(result,inputNumber); i++)
{
result = i*inputNumber;
}
Print(result);
IsOk method is here:
bool IsOk(int result, int inputNumber)
{
if(result%inputNumber!=0)
return false;
if(result.ToString().Replace("9",string.Empty).Replace("0",string.Empty).Length!=0)
return false;
return true;
}
My first solution has very bad performance, because of converting a number to string and looking for characters '9' and '0'.
New solution:
My new solution has very good performance and is a technical approach since of using Breadth-first search(BFS).
Algorithm of this solution:
For every input number, test 9, if it is answer print it, else add 2 child numbers (90 & 99) to queue, and continue till finding answer.
int inputNumber = 5;/*Or every other number, you can get this number from input.*/
long result;
var q = new Queue<long>();
q.Enqueue(9);
while (true)
{
result = q.Dequeue();
if (result%inputNumber == 0)
{
Print(result);
break;
}
q.Enqueue(result*10);
q.Enqueue(result*10 + 9);
}
Trace of number creation:
9
90,99
900,909,990,999
9000,9009,9090,9099,9900,9909,9990,9999
.
.
.
I wrote this code for console, and i used goto command however it is not prefered but i could not write it with only for.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace main
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter your number");
Int64 x = Convert.ToInt64(Console.ReadLine());
Int64 y, j, i, k, z = x;
x = x + 5;
loop:
x++;
for (i = 0, y = x; y != 0; i++)
y /= 10;
for (j = x, k = i; k != 0; j /= 10, k--)
{
if (j % 10 != 9)
if (j % 10 != 0)
goto loop;
}
if (x % z != 0)
goto loop;
Console.WriteLine("answer:{0}",x);
Console.ReadKey();
}
}
}

Categories

Resources