📌  相关文章
📜  在未排序的数组中找到奇数出现的两个数字

📅  最后修改于: 2022-05-13 01:57:52.375000             🧑  作者: Mango

在未排序的数组中找到奇数出现的两个数字

给定一个未排序的数组,其中包含除两个数字之外的所有数字的偶数次出现。找出在 O(n) 时间复杂度和 O(1) 额外空间中出现奇数的两个数字。

例子:

Input: {12, 23, 34, 12, 12, 23, 12, 45}
Output: 34 and 45

Input: {4, 4, 100, 5000, 4, 4, 4, 4, 100, 100}
Output: 100 and 5000

Input: {10, 20}
Output: 10 and 20

解决此问题的一种简单方法是运行两个嵌套循环。外循环选择一个元素,内循环计算所选择元素的出现次数。如果出现次数为奇数,则打印该数字。该方法的时间复杂度为 O(n^2)。

我们可以使用排序来获得 O(nLogn) 时间内出现的奇数。首先使用 O(nLogn) 排序算法对数字进行排序,例如合并排序、堆排序等。一旦对数组进行排序,我们需要做的就是对数组进行线性扫描并打印奇数出现的数字。

我们也可以使用散列。创建一个包含元素及其计数的空哈希表。一个一个地选择输入数组的所有元素。在哈希表中查找选取的元素。如果在哈希表中找到该元素,则增加其在表中的计数。如果没有找到该元素,则将其输入到哈希表中,计数为1。当所有元素都输入到哈希表中后,扫描哈希表并打印奇数个元素。这种方法平均可能需要 O(n) 时间,但它需要 O(n) 额外空间。

使用 XOR 的 AO(n) 时间和 O(1) 额外空间解决方案:
让两个奇数出现的数字是 x 和 y。我们使用按位异或来得到 x 和 y。我们尝试创建 2 个组,使 x 和 y 进入不同的组。例如 [a, a, b, b, x ], .那么问题就变成了“在未排序的数组中找到奇数出现的‘一个’数”,这变成了一个简单的问题,将使用 XOR 来解决。以下是对 x 和 y 进行不同分组的步骤。

1.第一步是对数组中存在的所有元素进行异或。由于 XOR 操作的以下属性,所有元素的 XOR 给我们 x 和 y 的 XOR。
1) 任意数 n 与自身的 XOR 给我们 0,即 n ^ n = 0
2) 任意数 n 与 0 的异或得到 n,即 n ^ 0 = n
3) XOR 是累积的和关联的。

所以我们在第一步之后有 x 和 y 的 XOR,以十进制形式。例如 5 ^ 6 返回 3,以位形式计算为 101 ^ 110 = 011。让 XOR 的“值”为 xor2。 xor2 中的每个Set 位**表示“x 和 y 中的相应位具有彼此不同的值”(XOR 属性-“位不同时为 1”)。

**(设置位是二进制形式的 1。例如 101 在第 0 个索引和第 2 个索引处有 2 个设置位(1)。)

例如,如果 x = 6 (0110) 和 y = 15 (1111),则 xor2 将是 (1001),xor2 中的两个设置位表示 x 和 y 中对应的位不同,在第 0 个索引处和在第 3 个索引处索引两者。

2.在第二步中,我们选择一组 xor2。想法是在 x 和 y 的位不同的索引中使用 xor2 为“1”的事实。因此,我们根据数字是否具有相同的设置位,将 x 和 y 以及列表的其余数字分成不同的组。

我们选择 xor2 的最右边的设置位,因为很容易获得一个数字的最右边的设置位(位魔术)。如果我们将一个数字与它的负数按位与,我们得到最右边的设置位。 (只是一个基于观察的属性,请记住)。所以, (xor2) & (-xor2)会给我们正确的设置位。通过 2 的补码查找 (-number),即 ((1's 补码) +1 )。它也可以写成 (~number)+1。

a) 2 的补码示例

7 是00111 (任何数量的前面的零)。 1 的补码是通过翻转位 11000 得到的。然后加 1,所以 7 的 2 的补码是11001 。由于第一位是1,它是一个负数。

(-1)*16 + 1*8 +1*1 = -7

b) (number) & (-number) = right set bit 的例子

7 的继续示例,7 是 00111,-7 是 11001,7 和 -7 是 00001。因此,7 的最右边设置位是 1。

12 & -12 的另一个例子:

12 是 01100 ** 并且 -12 是通过翻转数字和加 1 来计算的。因此,10011 和加 1 得到 10100。12 和 -12、01100 和 10100 给出 00100 作为设置位,在十进制系统中也返回为 4在这里称为设置位号

**(由于数字是 32 位,“left set-bit”的左边有 28 个 0,但只取几个是可以的。正数有最左边的位 0,负数有 1)

3.第三步,我们将 x 和 y 分成不同的组:我们现在知道对于选定的设置位索引,x 和 y 有不同的对应位。如果我们将列表中的所有数字与设置位相加,一些会给出 0,而另一些会给出 1。我们会将所有给出零的数字放在一组中,而将一放在另一组中。 x 和 y 将属于不同的组。

举例说明:-

例如 arr = [4, 2, 4, 10, 2, 3, 3, 12] ,

步骤 1) 所有在 arr 中的 XOR 将取消所有重复的 no。 10 ^12 将是 ans。 1010 ^ 1100 将是 0110,即 xor=6。

步骤 2) 从可视化的 01 10中设置位为 10。 (number) & (-number) 也是一种快速找到正确设置位的方法。

xor & (-xor) 可以直接编码。 6 是 0110,通过翻转数字并加 1 找到 -6,1001 +1 = 1010。

所以 6 AND -6 本质上是 0110 和 1010,即 00 10即 2 – 设置位数。

步骤 3) 将列表中的所有内容与 2(设置位号)相加,将给我们提供 1 或 0 的数字,然后我们进行分组。

[4, 4, 12] 和 [2, 10, 2, 3, 3],在 AND 上分别给出 0 和 1 与设置位数。

第 4 步)第 1 组的 XOR 将给我们 x=12,x ^ y 从第 1 步即 6 已知。x ^(x ^y) 将给我们 y。 12 ^6 是 10。

x=12, y=10

由于 XOR 的相同属性,此步骤有效。一个数字的所有出现都将放在同一个集合中。所有出现偶数次的数字的 XOR 将导致其集合中的 0。并且集合的异或将是奇数出现的元素之一。

C++
// C++ Program to find the two odd occurring elements
#include 
using namespace std;
 
/* Prints two numbers that occur odd number of times. The
function assumes that the array size is at least 2 and
there are exactly two numbers occurring odd number of times. */
void printTwoOdd(int arr[], int size)
{
    int xor2 = arr[0]; /* Will hold XOR of two odd occurring elements */
    int set_bit_no; /* Will have only single set bit of xor2 */
    int i;
    int n = size - 2;
    int x = 0, y = 0;
     
    /* Get the xor of all elements in arr[]. The xor will basically
        be xor of two odd occurring elements */
    for(i = 1; i < size; i++)
        xor2 = xor2 ^ arr[i];
     
    /* Get one set bit in the xor2. We get rightmost set bit
        in the following line as it is easy to get */
    set_bit_no = xor2 & ~(xor2-1);
     
    /* Now divide elements in two sets:
        1) The elements having the corresponding bit as 1.
        2) The elements having the corresponding bit as 0. */
    for(i = 0; i < size; i++)
    {
        /* XOR of first set is finally going to hold one odd
        occurring number x */
        if(arr[i] & set_bit_no)
        x = x ^ arr[i];
     
        /* XOR of second set is finally going to hold the other
        odd occurring number y */
        else
        y = y ^ arr[i];
    }
 
    cout << "The two ODD elements are " << x << " & " << y;
}
 
/* Driver code */
int main()
{
    int arr[] = {4, 2, 4, 5, 2, 3, 3, 1};
    int arr_size = sizeof(arr)/sizeof(arr[0]);
    printTwoOdd(arr, arr_size);
    return 0;
}
 
// This is code is contributed by rathbhupendra


C
// Program to find the two odd occurring elements
#include
 
/* Prints two numbers that occur odd number of times. The
   function assumes that the array size is at least 2 and
   there are exactly two numbers occurring odd number of times. */
void printTwoOdd(int arr[], int size)
{
  int xor2 = arr[0]; /* Will hold XOR of two odd occurring elements */
  int set_bit_no;  /* Will have only single set bit of xor2 */
  int i;
  int n = size - 2;
  int x = 0, y = 0;
 
  /* Get the xor of all elements in arr[]. The xor will basically
     be xor of two odd occurring elements */
  for(i = 1; i < size; i++)
    xor2 = xor2 ^ arr[i];
 
  /* Get one set bit in the xor2. We get rightmost set bit
     in the following line as it is easy to get */
  set_bit_no = xor2 & ~(xor2-1);
 
  /* Now divide elements in two sets:
    1) The elements having the corresponding bit as 1.
    2) The elements having the corresponding bit as 0.  */
  for(i = 0; i < size; i++)
  {
     /* XOR of first set is finally going to hold one odd
       occurring number x */
    if(arr[i] & set_bit_no)
      x = x ^ arr[i];
 
     /* XOR of second set is finally going to hold the other
       odd occurring number y */
    else
      y = y ^ arr[i];
  }
 
  printf("\n The two ODD elements are %d & %d ", x, y);
}
 
/* Driver program to test above function */
int main()
{
  int arr[] = {4, 2, 4, 5, 2, 3, 3, 1};
  int arr_size = sizeof(arr)/sizeof(arr[0]);
  printTwoOdd(arr, arr_size);
  getchar();
  return 0;
}


Java
// Java program to find two odd
// occurring elements
 
import java.util.*;
 
class Main
{  
      
    /* Prints two numbers that occur odd
       number of times. The function assumes
       that the array size is at least 2 and
       there are exactly two numbers occurring
       odd number of times. */
    static void printTwoOdd(int arr[], int size)
    {
      /* Will hold XOR of two odd occurring elements */   
      int xor2 = arr[0];
       
      /* Will have only single set bit of xor2 */
      int set_bit_no; 
      int i;
      int n = size - 2;
      int x = 0, y = 0;
      
      /* Get the xor of all elements in arr[].
         The xor will basically be xor of two
         odd occurring elements */
      for(i = 1; i < size; i++)
        xor2 = xor2 ^ arr[i];
      
      /* Get one set bit in the xor2. We get
         rightmost set bit in the following
         line as it is easy to get */
      set_bit_no = xor2 & ~(xor2-1);
      
      /* Now divide elements in two sets:
            1) The elements having the
               corresponding bit as 1.
            2) The elements having the
               corresponding bit as 0.  */
      for(i = 0; i < size; i++)
      {
         /* XOR of first set is finally going
            to hold one odd occurring number x */
        if((arr[i] & set_bit_no)>0)
          x = x ^ arr[i];
      
         /* XOR of second set is finally going
            to hold the other odd occurring number y */
        else
          y = y ^ arr[i];
      }
      
      System.out.println("The two ODD elements are "+
                                        x + " & " + y);
    }
     
    // main function
    public static void main (String[] args)
    {
        int arr[] = {4, 2, 4, 5, 2, 3, 3, 1};
        int arr_size = arr.length;
        printTwoOdd(arr, arr_size);
    }
}


Python3
# Python3 program to find the
# two odd occurring elements
 
# Prints two numbers that occur odd
# number of times. The function assumes
# that the array size is at least 2 and
# there are exactly two numbers occurring
# odd number of times.
def printTwoOdd(arr, size):
     
    # Will hold XOR of two odd occurring elements
    xor2 = arr[0]
     
    # Will have only single set bit of xor2
    set_bit_no = 0 
    n = size - 2
    x, y = 0, 0
 
    # Get the xor of all elements in arr[].
    # The xor will basically be xor of two
    # odd occurring elements
    for i in range(1, size):
        xor2 = xor2 ^ arr[i]
 
    # Get one set bit in the xor2. We get
    # rightmost set bit in the following
    # line as it is easy to get
    set_bit_no = xor2 & ~(xor2 - 1)
 
    # Now divide elements in two sets:
    # 1) The elements having the corresponding bit as 1.
    # 2) The elements having the corresponding bit as 0.
    for i in range(size):
     
        # XOR of first set is finally going to 
        # hold one odd  occurring number x
        if(arr[i] & set_bit_no):
            x = x ^ arr[i]
 
        # XOR of second set is finally going
        # to hold the other odd occurring number y
        else:
            y = y ^ arr[i]
 
    print("The two ODD elements are", x, "&", y)
 
# Driver Code
arr = [4, 2, 4, 5, 2, 3, 3, 1]
arr_size = len(arr)
printTwoOdd(arr, arr_size)
 
# This code is contributed by Anant Agarwal.


C#
// C# program to find two odd
// occurring elements
using System;
 
class main
{  
       
    // Prints two numbers that occur
    // odd number of times. Function
    // assumes that array size is at
    // least 2 and there are exactly
    // two numbers occurring odd number
    // of times.
    static void printTwoOdd(int []arr, int size) {
    
      // Will hold XOR of two odd
      //occurring elements  
      int xor2 = arr[0];
        
      // Will have only single set
      // bit of xor2
      int set_bit_no; 
      int i;
       
      //int n = size - 2;
      int x = 0, y = 0;
       
      // Get the xor of all the elements
      // in arr[].The xor will basically
      // be xor of two odd occurring
      // elements
      for(i = 1; i < size; i++)
        xor2 = xor2 ^ arr[i];
       
      // Get one set bit in the xor2.
      // We get rightmost set bit in
      // the following line as it is
      // to get.
         set_bit_no = xor2 & ~(xor2-1);
       
      // divide elements in two sets:
      // 1) The elements having the
      // corresponding bit as 1.
      // 2) The elements having the
      // corresponding bit as 0.
      for(i = 0; i < size; i++)
      {
         // XOR of first set is finally
         // going to hold one odd
         // occurring number x
            if((arr[i] & set_bit_no)>0)
            x = x ^ arr[i];
       
            // XOR of second set is finally
            // going to hold the other
            // odd occurring number y
            else
            y = y ^ arr[i];
      }
       
      Console.WriteLine("The two ODD elements are "+
                                        x + " & " + y);
    }
      
    // main function
    public static void Main()
    {
        int []arr = {4, 2, 4, 5, 2, 3, 3, 1};
        int arr_size = arr.Length;
        printTwoOdd(arr, arr_size);
    }
}
 
//This code is contributed by Anant Agarwal.


PHP


Javascript


C++
// C++ Program to find the two odd occurring elements
#include 
using namespace std;
 
/* Prints two numbers that occur odd number of times. The
function assumes that the array size is at least 2 and
there are exactly two numbers occurring odd number of times.
*/
 
void printTwoOdd(int arr[], int size)
{
    /*Create map and calculate frequency of array of
     * elements using array.*/
 
    unordered_map m;
    for (int i = 0; i < size; i++) {
        m[arr[i]]++;
    }
 
    /*Traverse through the map and check if its second
      element that is the frequency is odd or not.Then this
      is the odd occurring element .Its is clearly mentioned
      in problem that there are only two odd occurring
      elements so this will print those two elements.*/
 
    cout << "The two ODD elements are ";
    for (auto& x : m) {
        if (x.second % 2 != 0)
            cout << x.first << ", ";
    }
}
 
/* Driver code */
int main()
{
    int arr[] = { 4, 2, 4, 5, 2, 3, 3, 1 };
    int arr_size = sizeof(arr) / sizeof(arr[0]);
    printTwoOdd(arr, arr_size);
    return 0;
}
 
// This is code is contributed by Abhishek


Java
// Java Program to find the two odd occurring elements
 
import java.util.*;
 
class GFG{
 
/* Prints two numbers that occur odd number of times. The
function assumes that the array size is at least 2 and
there are exactly two numbers occurring odd number of times.
*/
 
static void printTwoOdd(int arr[], int size)
{
    /*Create map and calculate frequency of array of
     * elements using array.*/
 
    HashMap m = new HashMap();
    for (int i = 0; i < size; i++) {
         if(m.containsKey(arr[i])){
                m.put(arr[i], m.get(arr[i])+1);
            }
            else{
                m.put(arr[i], 1);
            }
    }
 
    /*Traverse through the map and check if its second
      element that is the frequency is odd or not.Then this
      is the odd occurring element .Its is clearly mentioned
      in problem that there are only two odd occurring
      elements so this will print those two elements.*/
 
    System.out.print("The two ODD elements are ");
    for (Map.Entry x : m.entrySet()) {
        if (x.getValue() % 2 != 0)
            System.out.print(x.getKey()+ ", ");
    }
}
 
/* Driver code */
public static void main(String[] args)
{
    int arr[] = { 4, 2, 4, 5, 2, 3, 3, 1 };
    int arr_size = arr.length;
    printTwoOdd(arr, arr_size);
}
}
 
 
// This code is contributed by 29AjayKumar


Python3
# Python3 program to find the two odd occurring elements
 
""" Prints two numbers that occur odd number of times.
The function assumes that the array size is at least 2
and there are exactly two numbers occurring odd number
of times.
"""
def printTwoOdd(arr, size):
    arr.sort()
     
    # Create map and calculate frequency of array
    # of elements using array.
    m = {}
    for i in range(size):
        if arr[i] not in m:
            m[arr[i]] = 0
             
        m[arr[i]] += 1
     
    """Traverse through the map and check if its second
    element that is the frequency is odd or not.Then this
    is the odd occurring element .Its is clearly mentioned
    in problem that there are only two odd occurring
    elements so this will print those two elements."""
    print("The two ODD elements are ", end = "")
    for x in m:
        if (m[x] % 2 != 0):
            print(x, end = ", ")
             
# Driver code
arr = [ 4, 2, 4, 5, 2, 3, 3, 1 ]
arr_size = len(arr)
 
printTwoOdd(arr, arr_size)
 
# This code is contributed by shubhamsingh10


C#
// C# program for the above approach
using System;
using System.Collections.Generic;
using System.Linq;
 
public class GFG {
     
/* Prints two numbers that occur odd number of times. The
function assumes that the array size is at least 2 and
there are exactly two numbers occurring odd number of times.
*/
static void printTwoOdd(int[] arr, int size)
{
    /*Create map and calculate frequency of array of
     * elements using array.*/
 
    Dictionary m = new Dictionary();
     for (int i = 0; i < size; i++)
        {
            if (m.ContainsKey(arr[i]))
                m[arr[i]]++;
            else
                m.Add(arr[i], 1);
        }
 
    /*Traverse through the map and check if its second
      element that is the frequency is odd or not.Then this
      is the odd occurring element .Its is clearly mentioned
      in problem that there are only two odd occurring
      elements so this will print those two elements.*/
 
    Console.Write("The two ODD elements are ");
    foreach (int x in m.Keys.ToList()){
        if (m[x] % 2 != 0)
            Console.Write(x + ", ");
    }
}
 
// Driver Code
public static void Main (string[] args) {
     
    int[] arr = { 4, 2, 4, 5, 2, 3, 3, 1 };
    int arr_size = arr.Length;
    printTwoOdd(arr, arr_size);
}
}
 
//  This code is contributed by splevel62.


Javascript


输出
The two ODD elements are 5 & 1

时间复杂度:O(n)
辅助空间:O(1)

另一种解决方案是使用地图 O(n) 时间和 O(n) 额外空间解决方案:

通过直接在 map 中而不是数组中获取输入,可以将额外空间 O(n) 最小化为 O(1)。

下面使用代码中的注释来解释这个想法 -

C++

// C++ Program to find the two odd occurring elements
#include 
using namespace std;
 
/* Prints two numbers that occur odd number of times. The
function assumes that the array size is at least 2 and
there are exactly two numbers occurring odd number of times.
*/
 
void printTwoOdd(int arr[], int size)
{
    /*Create map and calculate frequency of array of
     * elements using array.*/
 
    unordered_map m;
    for (int i = 0; i < size; i++) {
        m[arr[i]]++;
    }
 
    /*Traverse through the map and check if its second
      element that is the frequency is odd or not.Then this
      is the odd occurring element .Its is clearly mentioned
      in problem that there are only two odd occurring
      elements so this will print those two elements.*/
 
    cout << "The two ODD elements are ";
    for (auto& x : m) {
        if (x.second % 2 != 0)
            cout << x.first << ", ";
    }
}
 
/* Driver code */
int main()
{
    int arr[] = { 4, 2, 4, 5, 2, 3, 3, 1 };
    int arr_size = sizeof(arr) / sizeof(arr[0]);
    printTwoOdd(arr, arr_size);
    return 0;
}
 
// This is code is contributed by Abhishek

Java

// Java Program to find the two odd occurring elements
 
import java.util.*;
 
class GFG{
 
/* Prints two numbers that occur odd number of times. The
function assumes that the array size is at least 2 and
there are exactly two numbers occurring odd number of times.
*/
 
static void printTwoOdd(int arr[], int size)
{
    /*Create map and calculate frequency of array of
     * elements using array.*/
 
    HashMap m = new HashMap();
    for (int i = 0; i < size; i++) {
         if(m.containsKey(arr[i])){
                m.put(arr[i], m.get(arr[i])+1);
            }
            else{
                m.put(arr[i], 1);
            }
    }
 
    /*Traverse through the map and check if its second
      element that is the frequency is odd or not.Then this
      is the odd occurring element .Its is clearly mentioned
      in problem that there are only two odd occurring
      elements so this will print those two elements.*/
 
    System.out.print("The two ODD elements are ");
    for (Map.Entry x : m.entrySet()) {
        if (x.getValue() % 2 != 0)
            System.out.print(x.getKey()+ ", ");
    }
}
 
/* Driver code */
public static void main(String[] args)
{
    int arr[] = { 4, 2, 4, 5, 2, 3, 3, 1 };
    int arr_size = arr.length;
    printTwoOdd(arr, arr_size);
}
}
 
 
// This code is contributed by 29AjayKumar

Python3

# Python3 program to find the two odd occurring elements
 
""" Prints two numbers that occur odd number of times.
The function assumes that the array size is at least 2
and there are exactly two numbers occurring odd number
of times.
"""
def printTwoOdd(arr, size):
    arr.sort()
     
    # Create map and calculate frequency of array
    # of elements using array.
    m = {}
    for i in range(size):
        if arr[i] not in m:
            m[arr[i]] = 0
             
        m[arr[i]] += 1
     
    """Traverse through the map and check if its second
    element that is the frequency is odd or not.Then this
    is the odd occurring element .Its is clearly mentioned
    in problem that there are only two odd occurring
    elements so this will print those two elements."""
    print("The two ODD elements are ", end = "")
    for x in m:
        if (m[x] % 2 != 0):
            print(x, end = ", ")
             
# Driver code
arr = [ 4, 2, 4, 5, 2, 3, 3, 1 ]
arr_size = len(arr)
 
printTwoOdd(arr, arr_size)
 
# This code is contributed by shubhamsingh10

C#

// C# program for the above approach
using System;
using System.Collections.Generic;
using System.Linq;
 
public class GFG {
     
/* Prints two numbers that occur odd number of times. The
function assumes that the array size is at least 2 and
there are exactly two numbers occurring odd number of times.
*/
static void printTwoOdd(int[] arr, int size)
{
    /*Create map and calculate frequency of array of
     * elements using array.*/
 
    Dictionary m = new Dictionary();
     for (int i = 0; i < size; i++)
        {
            if (m.ContainsKey(arr[i]))
                m[arr[i]]++;
            else
                m.Add(arr[i], 1);
        }
 
    /*Traverse through the map and check if its second
      element that is the frequency is odd or not.Then this
      is the odd occurring element .Its is clearly mentioned
      in problem that there are only two odd occurring
      elements so this will print those two elements.*/
 
    Console.Write("The two ODD elements are ");
    foreach (int x in m.Keys.ToList()){
        if (m[x] % 2 != 0)
            Console.Write(x + ", ");
    }
}
 
// Driver Code
public static void Main (string[] args) {
     
    int[] arr = { 4, 2, 4, 5, 2, 3, 3, 1 };
    int arr_size = arr.Length;
    printTwoOdd(arr, arr_size);
}
}
 
//  This code is contributed by splevel62.

Javascript


输出
The two ODD elements are 1, 5, 

时间复杂度:O(n)

辅助空间:O(n)