Let's say we have a list of Node objects with a Value property.
Is there a time-efficient algorithm to link Node pairs of the same Value within the longest repeated Node-range(s) only?
Overlapping is allowed so is multiple longest node-pair spans if they have the same length.
The Value property is irreducible to char and therefore the "longest repeated substring" algorithm is not the answer.
Example:
INPUT:
Node Values =
{ AA, BB, CC, DD, AA, BB, CC, AA, BB, CC, DD, EE, BB, CC, DD, EE, FF, EE, FF } // Values
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 // indices
OUTPUT:
Edges (from_node_index, to_node_index) =
{
(00-07, 01-08, 02-09, 03-10),
(08-12, 09-13, 10-14, 11-15),
(15-17, 16-18)
}
Here is my naive attempt using C# which I think runs in O(n^2 log n) time complexity.
for (int i = 0; i < m_nodes.Count - 1; i++)
{
int first_j = -1;
int range = 0; // maximum number of repeated nodes in node range
int k = 0; // current number of repeated nodes in node range
for (int j = i + 1; j < m_nodes.Count; j++)
{
if (m_nodes[i].Value == m_nodes[j].Value)
{
k = 0;
do
{
k++;
if ((j + k) == m_nodes.Count) break;
} while (m_nodes[i + k].Value == m_nodes[j + k].Value);
if (k > range)
{
range = k;
first_j = j;
j += range; // skip repeating nodes
}
}
}
if (range > 0)
{
if (first_j > i)
{
for (int x = 0; x < range; x++)
{
if (first_j >= 0)
{
Edge edge = new Edge();
if (edge != null)
{
edge.Id = ++count;
edge.Source = m_nodes[i + x];
edge.Target = m_nodes[first_j + x];
edge.Label = m_nodes[first_j + x].Text + " = " + m_nodes[first_j + x].Value.ToString();
edge.Range = range;
edge.NumberInRange = x + 1;
m_edges.Add(edge);
}
}
}
}
}
}
I feel Dynamic Programming might be the answer but I am not familiar with that.
Here is the full source code: https://yadi.sk/d/aDdN9slB0H7BQA
Thank you in advance.
Related
Is there an algorithm for calculating a factorial without using System.Numerics library? We receive an int number and we need to return factorial of this number as string(if n = 30, we should return "265252859812191058636308480000000", if n = 70, we should return "11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000" ect. Numbers are very big)
I tried to find out, did anyone already write an article about that, but I didn't find anything.
It suffices to implement multiplication of a large number as a string by a small integer.
Illustration: 12! = 11! x 12 is obtained by multiplying every digit by 12 and summing (with shifts):
39916800
36
108
108
12
72
96
0
0
---------
479001600
A lazy solution. It is possible to evaluate the factorial with just BigNum addition, replacing the multiplications by successive additions. (For n!, we will perform 1+2+3+...n-1 additions. This is acceptable for moderate n.)
The computation uses two pre-allocated string (arrays of char), which are initially filled with null bytes (Writeline skips them). When adding from right to left, we stop when we meet a null.
int n = 20;
// Factorial and temporary string; 100! fits in 158 digits
const int N = 158;
char[] f = new char[N], t = new char[N];
f[N - 1] = '1'; // 1!
// Product up to n by successive additions
for (int i = 2; i <= n; i++)
{
// t= f
f.CopyTo(t, 0);
for (int j = 0; j < i - 1; j++)
{
// f+= t, repeated i-1 times
int c = 0; // Carry
for (int k = N - 1; k >= 0; k--)
{
if (t[k] == 0 && c == 0) break; // Significant part exhausted
int d = Math.Max(0, t[k] - '0') + Math.Max(0, f[k] - '0') + c;
c= d / 10; d = d % 10; f[k] = (char)(d + '0'); // Next carry/digit
}
}
Console.WriteLine(f);
}
Output:
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
static string FindFactorial(int n)
{
int[] result = new int[500000];
result[0] = 1;
int resultSize = 1;
for (int x = 2; x <= n; x++)
resultSize = Multiply(x, result, resultSize);
string factorial = "";
for (int i = resultSize - 1; i >= 0; i--)
factorial += result[i].ToString();
return factorial;
}
static int Multiply(int x, int[] result, int resultSize)
{
int carry = 0;
for (int i = 0; i < resultSize; i++)
{
int product = result[i] * x + carry;
result[i] = product % 10;
carry = product / 10;
}
while (carry != 0)
{
result[resultSize] = carry % 10;
carry /= 10;
resultSize++;
}
return resultSize;
}
This will work
public static void Main(string[] args)
{
string text = Console.ReadLine();
int number = 0;
int powerOfFive = 1;
const string coders = " 0Oo1l";
const int five = 5;
for (int i = text.Length - 1; i >= 0; --i)
{
int decodedDigit = coders.IndexOf(text[i]);
number += powerOfFive * decodedDigit;
powerOfFive *= five;
}
Console.Write(number);
}
For input data:
11 ll 00 O OO oO o 10
The console will display:
24 30 6 2 12 17 3 21
In my code I can only take one pair of characters (except the case when there are single character) separated by a space at one input at a time.
How can I take the entire string in one input?
Looks like you are supposed to split the input string on space and then process each substring individually.
string text = Console.ReadLine();
const string coders = " 0Oo1l";
const int five = 5;
foreach (var code in text.Split(' '))
{
int number = 0;
int powerOfFive = 1;
for (int i = code.Length - 1; i >= 0; --i)
{
int decodedDigit = coders.IndexOf(code[i]);
number += powerOfFive * decodedDigit;
powerOfFive *= five;
}
Console.Write(number + " ");
}
Sample input/output:
11 ll 00 O OO oO o 10
24 30 6 2 12 17 3 21
I'm trying to make a lottery console app, but have a problem with duplicated numbers in some rows.
A lottery coupon is 10 row with 7 numbers, min number is 0, max number is 36.
How can i check if the number is exist in same row in my for loop?
here is my code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obligatorisk_Opgave_2
{
class Program
{
static void Main(string[] args)
{
int min = 0; // minimum number
int max = 36; // maximum number
int rows = 10; // number of rows in my copun
int col = 7; // number of column in my copun
// Get the date of PC
string NameDate;
NameDate = DateTime.Now.ToString("yyyy.MM.dd");
string Week = "1-uge";
string ComName = "LYN LOTTO";
Random rnd = new Random();
Console.WriteLine("{0,22} \n {1,15} \n{2,18}", NameDate, Week, ComName);
for (int i = 0; i < rows; i++)
{
Console.Write($"{i + 1}.");
for (int j = 0; j < col; j++)
Console.Write("{1,4}", i, rnd.Next(min, max));
Console.WriteLine();
}
Console.WriteLine("***** JOKER TAL *****");
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < col; j++)
Console.Write("{0,4}", rnd.Next(1,9));
Console.WriteLine();
}
}
}
}
You can use a recursive function to do this:
private static List<int> GetRandomRow(List<int> row, int colCount, int min, int max)
{
if(colCount <= 0)
{
return row;
}
var next = rnd.Next(min, max);
if(row.Contains(next))
{
return GetRandomRow(row, colCount, min, max);
}
row.Add(next);
return GetRandomRow(row, colCount - 1, min, max);
}
Then you can use your program like:
private static Random rnd = new Random();
static void Main(string[] args)
{
int min = 0; // minimum number
int max = 36; // maximum number
int rows = 10; // number of rows in my copun
int col = 7; // number of column in my copun
// Get the date of PC
string NameDate;
NameDate = DateTime.Now.ToString("yyyy.MM.dd");
string Week = "1-uge";
string ComName = "LYN LOTTO";
Random rnd = new Random();
Console.WriteLine("{0,22} \n {1,15} \n{2,18}", NameDate, Week, ComName);
for (int i = 0; i < rows; i++)
{
Console.Write($"{i + 1}.");
var row = new List<int>();
var currentRow = GetRandomRow(row, col, min, max);
foreach (var currentCol in currentRow)
{
Console.Write("{1,4}", i, currentCol);
}
Console.WriteLine();
}
Console.WriteLine("***** JOKER TAL *****");
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < col; j++)
Console.Write("{0,4}", rnd.Next(1, 9));
Console.WriteLine();
}
}
Instead of random numbers you could Shuffle your List.
Shuffle Function:
public static List<T> Shuffle<T> (List<T> list) {
Random rnd = new Random();
for (int i = 0; i < list.Count; i++)
{
int k = rnd.Next(0, i);
T value = list[k];
list[k] = list[i];
list[i] = value;
}
return list;
}
Now you can call that function and shuffle the content of your List.
Example:
int min = 0;
int max = 36;
int rows = 10;
List<int> mylist = new List<int>();
for (int i = max; i >= min; i--) {
mylist.Add(i);
}
mylist = Shuffle(mylist);
for (int i = 0; i < rows; i++) {
Console.WriteLine(mylist[i]);
}
Console.ReadLine();
simply you can define variable from string data type and add each column in this variable but before add operation you should check if this column exists in this string or not
code is updated
i have definde rndNumber as an integer type before check then i have assigned rnd.Next(min, max) to it, because if i check for rnd.Next(min, max) and if it was not exist so when add it in checkNumber may be it changed again for example...
if(checkNumber.Contains(rnd.Next(min, max))) // if value of rnd.Next(min, max) was 15 and this number not exist in checkNumber so i can add it
{
checkNumber += rnd.Next(min, max); // maybe value of rnd.Next(min, max) change to will be 20
}
notice that every time you call rnd.Next(min, max) it's value will be changed
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obligatorisk_Opgave_2
{
class Program
{
static void Main(string[] args)
{
int min = 0; // minimum number
int max = 36; // maximum number
int rows = 10; // number of rows in my copun
int col = 7; // number of column in my copun
string checkColumn = ""; // string variable for storing rows values
// Get the date of PC
string NameDate;
NameDate = DateTime.Now.ToString("yyyy.MM.dd");
string Week = "1-uge";
string ComName = "LYN LOTTO";
Random rnd = new Random();
Console.WriteLine("{0,22} \n {1,15} \n{2,18}", NameDate, Week, ComName);
for (int i = 0; i < rows; i++)
{
Console.Write($"{i + 1}.");
for (int j = 0; j < col; j++)
{
// check here if string does not contains this random value then add this it into string and write this number, else will be written duplicated number
int rndNumber = rnd.Next(min, max);
if ( !checkColumn.Contains(rndNumber.ToString()+", ") )
{
checkColumn += rndNumber.ToString()+", ";
Console.Write("{1,4}", i, rndNumber);
}
else
{
Console.Write("duplicated number");
}
}
checkColumn += "\n";
Console.WriteLine();
}
Console.WriteLine("***** JOKER TAL *****");
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < col; j++)
Console.Write("{0,4}", rnd.Next(1,9));
Console.WriteLine();
}
}
}
}
I'd use something more like:
for (int i = 1; i <= rows; i++)
{
Console.Write((i + ".").PadRight(3));
var row = Enumerable.Range(min, (max - min) + 1).OrderBy(x => rnd.Next()).Take(col).ToList();
foreach(var num in row) {
Console.Write(num.ToString("00").PadLeft(3));
}
Console.WriteLine();
}
Producing:
1. 33 14 24 27 07 29 30
2. 12 31 03 19 04 02 30
3. 34 03 14 23 20 09 04
4. 09 11 24 07 00 30 17
5. 26 04 22 02 25 20 12
6. 28 26 12 08 04 25 35
7. 09 26 20 34 17 03 23
8. 25 26 35 08 29 06 01
9. 29 33 00 04 09 35 36
10. 00 14 19 25 03 21 33
I am trying to put the values of a matrix into an array in a specific order. The matrix is 2*length, where the length is the length of the message chosen by the user divided by two. The array is the entire length.
I have attempted using a for-loop where the first two values of the matrix ([0, 0] and [1, 0]) are put in the array.
Int[,] result = new int[2, length/2];
String[] resultArray = new string[length];
tracker = 0;
while (tracker < length)
{
for (int i = 0; i < length/2; i++)
{
resultArray[2*i] = Convert.ToString(result[0, i]);
resultArray[(2*i)+1] = Convert.ToString(result[1, i]);
}
tracker++;
}
When I run this code, I get the System.IndexOutOfRangeException: 'Index was outside the bounds of the array.' error message. The second expression in the for-loop is highlited.
I can't seem to realize what I've done wrong. (2*i)+1 when i=(length/2-1) should equal length-1, right?
Not a explicit answer, but way more fault proof than your aproach: to iterate trough a square matrix you can use
var y = i / d
var x = i % d
where d is the dimension of the array
int d = 2;
int length = d * d; // square matrix;
for (int i = 0; i < length; i++)
{
// iterate trough the array via column -> row by row (or horizontal)
int y = i / d;
int x = i % d; // => i mod 2 (remnant of division by 2)
resultArray[i] = Convert.ToString(result[x, y]);
}
for (int i = 0; i < length; i++)
{
// iterate trough the array via row -> column by column (or vertical)
int x = i / d;
int y = i % d;
resultArray[i] = Convert.ToString(result[x, y]);
}
You can actually iterate over a matrix using LINQ. You just need to use Cast<T>() to get the right IEnumerable interface then use a simple Select. It'll iterate over the first dimension first and within that iterate over the second dimension.
If I set up test data like this:
int[,] result = new int[2, 5];
result[0,0] = 00;
result[0,1] = 01;
result[0,2] = 02;
result[0,3] = 03;
result[0,4] = 04;
result[1,0] = 10;
result[1,1] = 11;
result[1,2] = 12;
result[1,3] = 13;
result[1,4] = 14;
Then this statement:
var resultArray1 = result.Cast<int>().Select( n => n.ToString("00")).ToArray();
Will yield these results:
00
01
02
03
04
10
11
12
13
14
If you wish to iterate over the second dimension first, you can write a short extension method:
public static IEnumerable<T> ToSingleDimension<T>(this T[,] source)
{
for (int i=0; i<=source.GetUpperBound(1); i++)
{
for (int j=0; j<=source.GetUpperBound(0); j++)
{
yield return source[j,i];
}
}
}
And call it like this:
var resultArray2 = result.ToSingleDimension().Select( n => n.ToString("00")).ToArray();
Which will yield these results:
00
10
01
11
02
12
03
13
04
14
See the example on DotNetFiddle.
You can use MathNet.Numerics library with some LINQ to achieve what you want:
PM > Install-Package MathNet.Numerics
var result = new double[2,4]
{
{ 1,2,3,4 },
{ 5,6,7,8 },
};
var resultArray = Matrix
.Build
.DenseOfArray(result)
.ToRowArrays()
.SelectMany(q => q.ToArray().Select(w => w.ToString()))
.ToArray();
You can use ToColumnArrays() if your initial array has shape [4,2] rather than [2,4]
I'm working on a math game in the Unity game engine using C#, specifically a reusable component to teach the grid method for multiplication. For example, when given the numbers 34 and 13, it should generate a 3X3 grid (a header column and row for the multiplier and multiplicand place values and 2X2 for the number of places in the multiplier and multiplicand). Something that looks like this:
My issue is that I don't know the best way to extract the place values of the numbers (eg 34 -> 30 and 4). I was thinking of just converting it to a string, adding 0s to the higher place values based on its index, and converting it back to an int, but this seems like a bad solution. Is there a better way of doing this?
Note: I'll pretty much only be dealing with positive whole numbers, but the number of place values might vary.
Thanks to all who answered! Thought it might be helpful to post my Unity-specific solution that I constructed with all the replies:
List<int> GetPlaceValues(int num) {
List<int> placeValues = new List<int>();
while (num > 0) {
placeValues.Add(num % 10);
num /= 10;
}
for(int i = 0;i<placeValues.Count;i++) {
placeValues[i] *= (int)Mathf.Pow(10, i);
}
placeValues.Reverse();
return placeValues;
}
Take advantage of the way our number system works. Here's a basic example:
string test = "12034";
for (int i = 0; i < test.Length; ++i) {
int digit = test[test.Length - i - 1] - '0';
digit *= (int)Math.Pow(10, i);
Console.WriteLine("digit = " + digit);
}
Basically, it reads from the rightmost digit (assuming the input is an integer), and uses the convenient place value of the way our system works to calculate the meaning of the digit.
test.Length - i - 1 treats the rightmost as 0, and indexes positive to the left of there.
- '0' converts from the encoding value for '0' to an actual digit.
Play with the code
Perhaps you want something like this (ideone):
int n = 76302;
int mul = 1;
int cnt = 0;
int res[10];
while(n) {
res[cnt++] = (n % 10) * mul;
mul*=10;
cout << res[cnt-1] << " ";
n = n / 10;
}
output
2 0 300 6000 70000
My answer is incredibly crude, and could likely be improved by someone with better maths skills:
void Main()
{
GetMulGrid(34, 13).Dump();
}
int[,] GetMulGrid(int x, int y)
{
int[] GetPlaceValues(int num)
{
var numDigits = (int)Math.Floor(Math.Log10(num) + 1);
var digits = num.ToString().ToCharArray().Select(ch => Convert.ToInt32(ch.ToString())).ToArray();
var multiplied =
digits
.Select((d, i) =>
{
if (i != (numDigits - 1) && d == 0) d = 1;
return d * (int)Math.Pow(10, (numDigits - i) - 1);
})
.ToArray();
return multiplied;
}
var xComponents = GetPlaceValues(x);
var yComponents = GetPlaceValues(y);
var arr = new int[xComponents.Length + 1, yComponents.Length + 1];
for(var row = 0; row < yComponents.Length; row++)
{
for(var col = 0; col < xComponents.Length; col++)
{
arr[row + 1,col + 1] = xComponents[col] * yComponents[row];
if (row == 0)
{
arr[0, col + 1] = xComponents[col];
}
if (col == 0)
{
arr[row + 1, 0] = yComponents[row];
}
}
}
return arr;
}
For your example of 34 x 13 it produces:
And for 304 x 132 it produces:
It spits this out as an array, so how you consume and display the results will be up to you.
For two-digit numbers you can use modulo
int n = 34;
int x = n % 10; // 4
int y = n - x; // 30