简体   繁体   English

正确判断一个 IList<int> 已经存在于 IList 中<ilist<int> > </ilist<int></int>

[英]Correctly determining if an IList<int> already exists in IList<IList<int>>

I'm using 3 iterators to iterate through an int[] object to find lists containing three int's that all sum to 0, without adding duplicate lists to the final return object. Once the iterators find a valid sequence, each array value that the iterator points to is added to a temporary IList object via syntax such as "tempList.Add(nums[a]);"我正在使用 3 个迭代器迭代 int[] object 以查找包含三个总和为 0 的 int 的列表,而不向最终返回 object 添加重复列表。一旦迭代器找到有效序列,迭代器的每个数组值指向通过诸如“tempList.Add(nums[a]);”之类的语法添加到临时 IList object etc. etc。 This tempList is then added to the final IList<IList> return object.然后将此 tempList 添加到最终 IList<IList> 返回 object。

To check for duplicates, I'm using the following sytax:要检查重复项,我使用以下语法:

if ((nums[c] + nums[a] + nums[b] == 0) && !answerList.Contains(tempList))

{
    answerList.Add(tempList);
}

This works when the IList<IList> is initially empty, however the second clause evaluated "false" for the following scenario, which is preventing the valid tempList from being added to the IList<IList> answerList:这在 IList<IList> 最初为空时起作用,但是第二个子句针对以下情况评估为“false”,这会阻止将有效的 tempList 添加到 IList<IList> answerList:

IList<IList<int>> == [[-1,0,1]]
tempList == [-1,-1,2]

Do I need to extend a Comparable interface to correct this?我是否需要扩展一个 Comparable 接口来纠正这个问题? I've double checked the array values for a, b and c and they collectively sum to 0, so I'm certain that it's the.Contains comparison that is causing issue.我已经仔细检查了 a、b 和 c 的数组值,它们的总和为 0,因此我确定是 the.Contains 比较导致了问题。

Here is the code:这是代码:


 public IList<IList<int>> ThreeSum(int[] nums) // maybe use three index pointers to fill triplet, one starting at index 0, one
                                                      // starting at index nums.Lenght - 1 and one starting near or at middle
                                                      // 5 billion possible combinations of triplets among array of 3001 triplets
        {
            IList<int> tempList = new List<int>();
            IList<IList<int>> answerList = new List<IList<int>>();
            int countPositive = 0;
            int countNegative = 0;
            bool addAnswerList = false;
            int indexPositive = 0;
            int a = 0;
            int b = 0;
            int c = 0;
            bool aExtreme = false;
            bool bExtreme = false;
            bool cExtreme = false;
            
                

            if (nums == null)
                return answerList;

            if (nums.Length == 0 /* || /* nums.Length < 3 */)
                return answerList;

            if (nums.Length == 1 && nums[0] == 0)
                return answerList;

            for (int i = 0; i < nums.Length; i++) // corner case where all array values are either postive or negative
                                                  // 0 sum triplet not possible
            {
                if (nums[i] > 0)
                    countPositive++;
                else if (nums[i] < 0)
                    countNegative++;    
            }

            if ((countPositive == nums.Length || countNegative == nums.Length) || (countNegative == 0 && countPositive == 0))
                return answerList;

            if (nums.Length < 51)
            {
                int temp = 0;
                
                for (int i = 1; i < nums.Length; i++) // use recursive sort to go through 3001 elements, use linear if less than 51
                {
                    temp = nums[i];
                    int j = i;

                    while (j > 0 && nums[j-1] > temp)
                    {
                        nums[j] = nums[j-1];
                        j--;
                    }
                    
                    nums[j] = temp; 
                   
                }
               
                Console.WriteLine(String.Join(" ", nums));

            }

            

             else if (nums.Length > 50) // recursive sort for larger input array
            {
                mergeSort(nums);
            }

            // Now nums is storted, 0 sum triplet will most likely be found where entries change from negative to positive
            for (int i = 0; i < nums.Length; i++)
            {
                if (nums[i] > 0)
                {
                  //  toPositive = true;
                    indexPositive = i;
                    break;
                }
                
            }

            Console.WriteLine(indexPositive);


            if (indexPositive == 0) // case to make sure accessors do not get invalid number
            {
                 a = 0;          // initialize other two index accessors in addition to indexPositive
                 b = 0;
            }
            else
            {
                 a = indexPositive - 1; // initialize other two index accessors in addition to indexPositive
                 b = indexPositive - 1;
            }

            c = indexPositive; // store initial indexPositive value into variable c as indexPositive will change
                               // throughtout the interation
            
            // if indexPositive is less than (nums.Length / 2), iterate two other accessors towards end of nums
            // else, interate two other accessors towards nums[0]

            if (c < (nums.Length / 2)) // use iterator c in place of indexPositive
            {
                while (c < nums.Length && b < nums.Length && a >= 0)
                {

                    if (a == 0 || a == nums.Length - 3)
                    {
                        aExtreme = true;
                    }
                    else
                    {
                        aExtreme = false;
                    }

                    if (b == 1 || b == nums.Length - 2)
                    {
                        bExtreme = true;
                    }
                    else
                    {
                        bExtreme = false;
                    }

                    if (c == 2 || c == nums.Length - 1)
                    {
                        cExtreme = true;
                    }
                    else
                    {
                        cExtreme = false;
                    }

                    if ((c != a && c != b && a != b) && (nums[c] + nums[a] + nums[b] == 0)) // if nums add to 0, add them to tempList
                    {
                        tempList.Add(nums[a]);
                        tempList.Add(nums[b]);
                        tempList.Add(nums[c]);
                    }

                   
                    
                    // need to check if exact triplet is duplicate or if tempList triplet contains same 3 values in different order
                    // 3 values in different order not an issues since input list is already sorted!!!!
                    // but need to be aware order accessors are added to temp list. Accessors cannot "crossover" one another!!!
                    if ((nums[c] + nums[a] + nums[b] == 0) && !answerList.Any(x => x.SequenceEqual(tempList)) /*!answerList.Contains(tempList)*/)
                        // Having issues, answerList.Contains does not currently do what is desired
                    {
                        answerList.Add(tempList);  // add tempList to answerList 
                        addAnswerList = true;
                    }

                    else
                    {
                        addAnswerList = false;
                    }

                    tempList.Clear();          // clear tempList to prepare for next entry

                    // Make changes here to make sure only 1 accessor iterates at a time, to check all possible and logical combinations
                    // Since array is now sorted, iteration towards sums[0] only has to continue if sum of 3 accessors is greater than 0
                    // Once active accessor returns a value that results in 0 sum, further iteration is guaranteed to return
                    // an identical triplet or one that sums to less than 0. At this point, the two accessors that are going in the same
                    // direction should be iterated by 1 position and the cycle repeated
                    
                    

                    if (nums[a] + nums[b] + nums[c] < 0) // still have chance to get to 0 value triplet with rightmost accessor
                                                                                   
                    {
                        c++;
                    }


                    else if ((addAnswerList == true) || nums[a] + nums[b] + nums[c] > 0) // no point in further iteration,
                                                                                         // reset 'c' accessor to original starting
                                                                                        // position and decrement other accessors by 1
                                                                                        // towards first array element
                    {                                                                   // to begin cycle again
                        c = indexPositive - 1;
                        b--;
                        a--;
                    }

                }
                
            }

            else  // a and b accessors are interated towards 0
            {
                while (c < nums.Length && a >= 0 && b >= 0)
                {
                    if (a == 0 || a == nums.Length - 3)
                    {
                        aExtreme = true;
                    }
                    else
                    {
                        aExtreme = false;
                    }

                    if (b == 1 || b == nums.Length - 2)
                    {
                        bExtreme = true;
                    }
                    else
                    {
                        bExtreme = false;
                    }

                    if (c == 2 || c == nums.Length - 1)
                    {
                        cExtreme = true;
                    }
                    else
                    {
                        cExtreme = false;
                    }


                    if ((c != a && c != b && a != b) && (nums[c] + nums[a] + nums[b] == 0))  // if nums add to 0, add them to tempList 
                                                                                                                                 // need to check if exact triplet is duplicate
                    {
                        tempList.Add(nums[a]);
                        tempList.Add(nums[b]);
                        tempList.Add(nums[c]);
                    }

                    Console.WriteLine(String.Join(" ", tempList));

                    

                    // need to check if exact triplet is duplicate or if tempList triplet contains same 3 values in different order
                    // 3 values in different order not an issues since input list is already sorted!!!!
                    // but need to be aware order accessors are added to temp list. Accessors cannot "crossover" one another!!!
                    if ((nums[c] + nums[a] + nums[b] == 0) && !answerList.Any(x => x.SequenceEqual(tempList)))
                    // Having issues, answerList.Contains does not currently do what is desired
                    {
                        answerList.Add(tempList);  // add tempList to answerList 
                        addAnswerList=true;
                    }

                    else
                    {
                        addAnswerList = false;
                    }

                    tempList.Clear();          // clear tempList to prepare for next entry

                    // Make changes here to make sure only 1 accessor iterates at a time, to check all possible and logical combinations
                    // Since array is now sorted, iteration towards sums[0] only has to continue if sum of 3 accessors is greater than 0
                    // Once active accessor returns a value that results in 0 sum, further iteration is guaranteed to return
                    // an identical triplet or one that sums to less than 0. At this point, the two accessors that are going in the same
                    // direction should be iterated by 1 position and the cycle repeated
                    
                    
                    if (nums[a] + nums[b] + nums[c] > 0) // still have chance to get to 0 value triplet with
                                                                                    // leftmost accessor
                    {
                        a--;
                    }
                    

                    else if ((addAnswerList == true) || nums[a] + nums[b] + nums[c] < 0) // no point in further iteration,
                                                                                         // reset 'a' accessor to original starting
                                                                                        // position and increment other accessors by 1
                                                                                        // towards last array element
                    {                                                                   // to begin cycle again
                        a = b; // a = indexPositive - 1;

                        if ((bExtreme == false && b < nums.Length - 2) && (cExtreme == false && c < nums.Length - 1)) 
                            // if there is still room to run towards end of array, increment, else decrement
                        {
                            b++;
                            c++;
                        }
                        else
                        {
                            bExtreme = true;
                            cExtreme = true;
                            a -= 2;
                            b--;

                        }
                        
                        
                    }
                }
            }

            Console.WriteLine(String.Join(" ", answerList));
            return answerList;  
            
           
        }

        public void merge(int[] array1, int[] array2, int[] outArray)
        {
            int i = 0;
            int j = 0;

            while (i + j < outArray.Length)
            {
                if (j == array2.Length || (i < array1.Length && (array1[i] < array2[j])))
                {
                    outArray[i + j] = array1[i++];
                }

                else
                {
                    outArray[i + j] = array2[j++];
                }
            }
        }

        public void mergeSort(int[] inputArray)
        {
            if (inputArray.Length < 2)
                return;

            int[] firstHalf = new int[inputArray.Length / 2];
            int[] secondHalf = new int[inputArray.Length / 2];

            for (int i = 0; i < (inputArray.Length / 2); i++)
            { 
                firstHalf[i] = inputArray[i]; 
            }

            for (int i = inputArray.Length / 2; i < inputArray.Length; i++)
            {
                secondHalf[i] = inputArray[i];
            }

            mergeSort(firstHalf);
            mergeSort(secondHalf);  
            
            merge(firstHalf, secondHalf, inputArray);

        }

You can replace你可以更换

answerList.Contains(tempList))

which checks only for reference equality, with它只检查引用相等性,与

answerList.Any(x => x.SequenceEqual(tempList))

which will run SequenceEqual on the answerList until it finds the first answer that has the same integer elements and returns false if none can be found.它将在answerList上运行SequenceEqual直到找到第一个具有相同 integer 元素的答案,如果找不到则返回 false。

Keep in mind that these functions require System.Linq .请记住,这些功能需要System.Linq

Credit: thanks Hans Kesting for suggesting Any(...) over FirstOrDefault(...) != null致谢感谢 Hans Kesting 建议Any(...)而不是FirstOrDefault(...) != null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM