可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am having trouble with a small bit of code, which in a random size array, with random number pairs, except one which has no pair.
I need to find that number which has no pair.
arLength is the length of the array. but i am having trouble actually matching the pairs, and finding the one which has no pair..
for (int i = 0; i <= arLength; i++) { // go through the array one by one.. var number = nArray[i]; // now search through the array for a match. for (int e = 0; e <= arLength; e++) { if (e != i) { } } }
I have also tried this :
var findValue = nArray.Distinct();
I have searched around, but so far, i haven't been able to find a method for this.
This code is what generates the array, but this question isn't about this part of the code, only for clarity.
Random num = new Random(); int check = CheckIfOdd(num.Next(1, 1000000)); int counter = 1; while (check <= 0) { if (check % 2 == 0) { check = CheckIfOdd(num.Next(1, 1000000)); ; } counter++; } int[] nArray = new int[check]; int arLength = 0; //generate arrays with pairs of numbers, and one number which does not pair. for (int i = 0; i < check; i++) { arLength = nArray.Length; if (arLength == i + 1) { nArray[i] = i + 1; } else { nArray[i] = i; nArray[i + 1] = i; } i++; }
回答1:
Distict
will give you back the array with distinct values. it will not find the value you need.
You can GroupBy
and choose the values with Count
modulo 2 equals 1.
var noPairs = nArray.GroupBy(i => i) .Where(g => g.Count() % 2 == 1) .Select(g=> g.Key);
回答2:
You can do it using the bitwise
operator ^
, and the complexity is O(n)
.
Theory
operator ^
aka xor
has the following table:

So suppose you have only one number without pair, all the pairs will get simplified because they are the same.
var element = nArray[0]; for(int i = 1; i < arLength; i++) { element = element ^ nArray[i]; }
at the end, the variable element
will be that number without pair.
回答3:
You can use a dictionary to store the number of occurrences of each value in the array. To find the value without pairs, look for a (single) number of occurrences smaller than 2.
using System.Linq; int[] data = new[] {1, 2, 3, 4, 5, 3, 2, 4, 1}; // key is the number, value is its count var numberCounts = new Dictionary<int, int>(); foreach (var number in data) { if (numberCounts.ContainsKey(number)) { numberCounts[number]++; } else { numberCounts.Add(number, 1); } } var noPair = numberCounts.Single(kvp => kvp.Value < 2); Console.WriteLine(noPair.Key);
Time complexity is O(n) because you traverse the array only a single time and then traverse the dictionary a single time. The same dictionary can also be used to find triplets etc.
.NET Fiddle
回答4:
An easy and fast way to do this is with a Frequency Table. Keep a dictionary with as key your number and as value the number of times you found it. This way you only have to run through your array once.
Your example should work too with some changes. It will be a lot slower if you have a big array.
for (int i = 0; i <= arLength; i++) { bool hasMatch = false; for (int e = 0; e <= arLength; e++) { if (nArray[e] == nArray[i])//Compare the element, not the index. { hasMatch = true; } } //if hasMatch == false, you found your item. }
回答5:
All you have to do is to Xor
all the numbers:
int result = nArray.Aggregate((s, a) => s ^ a);
all items which has pair will cancel out: a ^ a == 0
and you'll have the distinc item: 0 ^ 0 ^ ...^ 0 ^ distinct ^ 0 ^ ... ^0 == distinct
回答6:
Because you mentioned you like short and simple in a comment, how about getting rid of most of your other code as well?
var total = new Random().Next(500000) * 2 + 1; var myArray = new int[total]; for (var i = 1; i < total; i+=2) { myArray[i] = i; myArray[i -1] = i; } myArray[total - 1] = total;
Then indeed use Linq to get what you are looking for. Here is a slight variation, returning the key of the item in your array:
var key = myArray.GroupBy(t => t).FirstOrDefault(g=>g.Count()==1)?.Key;