【问题标题】:Sorted squares of numbers in a list in O(n)?O(n)中列表中的数字平方排序?
【发布时间】:2018-03-28 19:12:10
【问题描述】:

给定一个按排序顺序排列的整数列表,例如[-9, -2, 0, 2, 3],我们必须对每个元素求平方并以排序顺序返回结果。因此,输出将是:[0, 4, 4, 9, 81]

我可以想出两种方法:

  1. O(NlogN) 方法 - 我们将每个元素的平方插入哈希集中。然后将元素复制到列表中,排序然后返回。

  2. O(n) 方法 - 如果输入元素有一个界限(比如 -100 到 -100),那么我们创建一个大小为 20000 的布尔列表(存储 -10000 到 10000)。对于每个输入元素,我们将相应的平方数标记为真。例如,对于输入中的9,我将布尔数组中的81 标记为真。然后遍历这个布尔列表,将所有真正的元素插入一个返回列表。请注意,在此我们做了一个假设 - 输入元素有一个界限。

有没有什么方法可以让我们在O(n) 时间内做到这一点即使不假设输入有任何界限

【问题讨论】:

  • 找到符号变化,将值平方,将列表解释为两个排序列表,然后merge them。那将是 O(n)。
  • @WarrenWeckesser,您能详细说明一下吗?
  • @J.Doe 以您的示例[-9, -2, 0, 2, 3] 为例,将其解释为[-9, -2][0, 2, 3](负数;非负数)。平方两个列表。 [81, 4][0, 4, 9]。逆向走第一个列表,正常走第二个列表,然后将它们合并。 :)
  • @Max,很有趣!我想知道为什么我没有想到那个。 :)
  • 另一种实现方式是在比较 abs(L[left]) 和 abs(L[right]) 后使用deque.appendleft 并决定放入哪个,并递增。左或右指针...(类似于@Lavina Khushlani 提到的。

标签: algorithm time-complexity


【解决方案1】:

我可以想到一个O(n) 方法

  1. 将输入分成 2 个列表。一个有负数的,我们称这个列表为A。一个是正​​数和 0,列出B。这是在保留输入顺序的同时完成的,这很简单:O(n)
  2. 反向列表A。我们这样做是因为一旦平方,如果翻转,元素之间的关系就会大于关系
  3. 将两个列表中的每一项放在适当的位置:O(n)
  4. 运行merge 操作与合并排序的操作不同。 :O(n)
  5. 总计:O(n)

完成:)

【讨论】:

  • Run a merge operation not unlike that of a merge sort. : O(n)。这是困难的一步。你如何合并它们?我希望你在谈论就地算法。
  • @Nawaz 我不确定你的意思,像合并排序这样的合并在 python 中是 5-10 行。另外,就地与非就地有何关系?
  • 如果您将其就地合并,则意味着您正在修改与另一个列表合并的同一个列表。你到底是怎么做到的?如果还是看不到,请尝试编写代码查看。
  • 你可以在不合并的情况下做到这一点,它仍然具有相同的时间复杂度。我没有针对空间进行优化,但这样做很简单。传统的合并排序也不是就地的。但是就地实现是可能的
  • 如果你不这样做,那么它是微不足道的。超级简单!然而,如果你这样做(使用O(1) 空间复杂度),那么这不是一件容易的事。如果您认为它仍然很容易,请尝试这样做并告诉我它是如何工作的。
【解决方案2】:

有没有什么方法可以在 O(n) 时间内完成,即使不假设输入有任何界限?

当然。

由于原始列表已经排序,您很幸运!

给定两个数字 x 和 y

如果|x| > |y| 那么x^2 > y^2

所以你所要做的就是将列表分成两部分,一部分用于所有负数,另一部分用于所有正数

把消极的反过来变成积极的

然后您使用插入将这两个列表合并为一个。这在O(n) 中运行,因为两个列表都已排序。

您可以从那里计算平方并将它们放入新列表中。

【讨论】:

    【解决方案3】:

    我们可以通过2指针技术来实现。 1 指针在开头,其他指针在结尾。比较正方形并相应地移动指针并开始在新列表的末尾分配最大元素。 时间 = O(n) 空间 = O(n)

    你能就地做吗?降低空间复杂度。

    【讨论】:

      【解决方案4】:

      这可以用 O(n) 的时间和空间来完成。我们需要两个指针。以下是Java代码:

      public int[] sortedSquares(int[] A) {
          int i = 0; 
          int j = A.length - 1;
      
          int[] result = new int[A.length];
      
          int count = A.length - 1;
          while(count >= 0) {
              if(Math.abs(A[i]) > Math.abs(A[j])) {
                  result[count] = A[i]*A[i];
                  i++;
              }
              else {
                  result[count] = A[j]*A[j];
                  j--;
              }
              count--;
          }
      
          return result;
      }
      

      从末尾开始比较绝对值。然后创建答案。

      【讨论】:

        【解决方案5】:
          class Solution {
                public int[] sortedSquares(int[] nums) {
                    int left = 0;
                    int right = nums.length -1;
                    int index = nums.length- 1;
                    int result[] = new int [nums.length];
                    while(left<=right)
                    {
                        if(Math.abs(nums[left])>Math.abs(nums[right]))
                        {
                            result[index] = nums[left] * nums[left];
                            left++;
                        }
                        else
                        {
                            result[index] = nums[right] * nums[right];
                            right--;
                        }
                        index--;
                    }
                    return result;
                }
            }
        

        通过使用朴素的方法,这个问题将非常简单,但需要 O(nlogn) 复杂度

        要在 O(n) 中解决这个问题,最好的方法是两个指针方法。

        1. 创建一个与给定数组长度相同的新结果数组,并将其指针存储为数组长度

        2. 在数组的开头分配一个指针,然后在数组的最后分配另一个指针,因为我们知道两边的最后一个元素将是最高的

           [-9, -2, 0, 2, 3]
          

          比较-9和3的绝对值

        3. 如果是左边的值,则将该值存储到结果数组中,并减少其索引值并增加左边,否则减少右边。

        【讨论】:

          【解决方案6】:

          Python3 解决方案。时间复杂度 - O(N) 和空间复杂度 O(1)。

          def sorted_squArrres(Arr:list) ->list:
              i = 0
              j = len(Arr)-1
          
              while i<len(Arr):
                  if Arr[i]*Arr[i]<Arr[j]*Arr[j]:
                      Arr.insert(0,Arr[j]*Arr[j])
                      Arr.pop(j+1)
                      i+=1
                      continue
          
                  if Arr[i]*Arr[i]>Arr[j]*Arr[j]:
                      Arr.insert(0,Arr[i]*Arr[i])
                      Arr.pop(i+1)
                      i+=1
                      continue
                  else:
                      if i!=j:
                          Arr.insert(0,Arr[j]*Arr[j])
                          Arr.insert(0,Arr[j+1]*Arr[j+1])
                          Arr.pop(j+2)
                          Arr.pop(i+2)
                          i+=2
                      else:
                          Arr.insert(0,Arr[j]*Arr[j])
                          Arr.pop(j+1)
                          i+=1
          
                      
           
              return Arr
                  
              
          X = [[-4,-3,-2,0,3,5,6],[1,2,3,4,5],[-5,-4,-3,-2,-1],[-9,-2,0,2,3]]
          for i in X:
              # looping differnt kinds of inputs
              print(sorted_squArrres(i))
          
          # outputs 
          '''
          [0, 4, 9, 9, 16, 25, 36]
          [1, 4, 9, 16, 25]
          [1, 4, 9, 16, 25]
          [0, 4, 4, 9, 81]
          '''
          

          【讨论】:

            猜你喜欢
            • 2017-01-19
            • 2012-05-22
            • 1970-01-01
            • 2012-06-24
            • 2022-01-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-16
            相关资源
            最近更新 更多