你是怎么做到的?值未排序但属于[1..n]
示例数组[3,1,2,5,7,8]
。答案:4, 6
我在另一个类似的post中看到了这个解决方案,但我不明白最后一步:
- 求数的总和S = a1 + ... + an。
- 还可以找到平方和T =a1²+ ... +an²。
- 你知道总和应该是S'= 1 + ... + n = n(n + 1)/ 2
- 你知道平方和应该是T'=1²+ ... +n²= n(n + 1)(2n + 1)/ 6.
- 现在建立以下方程组x + y = S'-S,x²+y²= T'-T。
- 通过写x 2 + y 2 =(x + y)2-2xy =>来解决。的xy =((S'-S)²-(T'-T))/ 2。
- 现在这些数字只是z中二次方的根:z²-(S'-S)z +((S'-S)²-(T'-T))/ 2 = 0。
在z为未知的最后一步中设置二次方程的解释是什么?解决这个问题背后的直觉是什么?
答案 0 :(得分:26)
此方法不可取,因为它遇到integer
溢出问题。因此,使用XOR
方法查找两个数字,这是非常高效的。如果你有兴趣,我可以解释一下。
根据下面@ordinary的请求,我正在解释算法:
修改强>
假设数组a[]
的最大元素是B
,即假设a[]={1,2,4}
,此处3
和5
不存在于[]中元素是B=5
。
xor
数组a
到X
xor
从1到B
到x
x
x = x &(~(x-1));
位集
a[i] ^ x == x
比xor
a[i]
改为p
,则xor
q
k
从1 B
k ^ x == x
xor
p
而xor
q
其他p
q
< / LI>
a = {1,2,4}
和B
<强>证明:强>
让XOR
和a
为5,即从1到5,缺少的数字是3和5
我们XOR
的{{1}}个元素和1到5的数字后,我们留下x
的3和5,即x
。
现在,当我们找到3--> 011
最左边的位集时,它只是3和5中最左边的位。(5 --> 101
,x = 010
和x = 3 ^ 5
x
)
在此之后,我们尝试根据p = 2 , 2 , 3 (all has the 2nd last bit set)
q = 1, 1, 4, 4, 5 (all has the 2nd last bit unset)
的位集分成两组,因此这两组将是:
XOR
如果我们p
之间3
的元素我们会找到xor
,而且q
我们public void findNumbers(int[] a, int B){
int x=0;
for(int i=0; i<a.length;i++){
x=x^a[i];
}
for(int i=1;i<=B;i++){
x=x^i;
}
x = x &(~(x-1));
int p=0, q=0;
for(int i=0;i<a.length;i++){
if((a[i] & x) == x){
p=p^a[i];
}
else{
q=q^a[i];
}
}
for(int i=1;i<=B;i++){
if((i & x) == x){
p=p^i;
}
else{
q=q^i;
}
}
System.out.println("p: "+p+" : "+q);
}
的所有元素都是{{1}}将获得5。
因此答案。
java中的代码
{{1}}
答案 1 :(得分:10)
让x和y成为二次方程的根。
SUM
= x + y PRODUCT
= x * y 如果我们知道总和和乘积,我们可以将二次方程重建为:
z^2 - (SUM)z + (PRODUCT) = 0
在你提到的算法中,我们找到总和和乘积,然后我们用上面的公式重建二次方程。
如果您对详细的推导感兴趣,here is a reference。阅读“从根的总和和乘积重构二次方程”。
答案 2 :(得分:5)
我有一个针对上述问题的算法。
假设
Actual Series: 1 2 3 4 5 6 a:sum=21 product= 720
Missing Number series: 1 * 3 4 * 6 b:sum=14 product= 72
a+b=21-14= 7 , ab=720/72=10
现在我们需要找到a-b= sqrt[(a+b)^2 -4ab]
。
如果你计算:
a-b= 3
现在
a+b=7
a-b=3
添加两个等式:
2a=10, a=5
然后b=7-5=2
因此,2
和5
丢失了。
答案 3 :(得分:4)
从
开始x+y == SUM
xy == PRODUCT
有两种情况。如果PRODUCT为零,则一个数字为0
,另一个为SUM
。否则两者都不为零;我们可以将第一个等式乘以x
而不改变相等性:
x*x + xy == x*SUM
代替第二个等式:
x*x + PRODUCT = x*SUM
以通常的形式重新排列
x*x - x*SUM + PRODUCT = 0
那样
x = SUM/2 + sqrt(SUM*SUM - 4*PRODUCT)/2
y = SUM/2 - sqrt(SUM*SUM - 4*PRODUCT)/2
答案 4 :(得分:2)
Java实施:(基于@Ben Voigt)
BigInteger fact=1;
int sum=0;
int prod=1;
int x,y; // The 2 missing numbers
int n=a.length;
int max=MIN_VALUE;
for (int i=0; i<a.length;i++){
sum+=a[i]; //sums the existing numbers
prod*=a[i]; //product the existing numbers
if (max<a[i]) //searches for the biggest number in the array
max=a[i];
}
while(max!=1){ //factorial for the maximum number
fact*=max;
max--;
}
sum=(n*(n+1))/2 - sum; //the sum of the 2 missing numbers
prod=fact/prod; //the product of the 2 missing numbers
x=sum/2 + Math.sqrt(sum*sum - 4*prod)/2;
y=sum/2 - Math.sqrt(sum*sum - 4*prod)/2;
答案 5 :(得分:1)
Below is the generic answer in java code for any number of missing numbers in a given array
//assumes that there are no duplicates
a = [1,2,3,4,5]
b = [1,2,5]
a-b=[3,4]
public list<integer> find(int[] input){
int[] a= new int[] {1,2,3,4,5};//create a new array without missing numbers
List<Integer> l = new ArrayList<Integer>();//list for missing numbers
Map<Integer,Integer> m = new HashMap<Integer>();
//populate a hashmap with the elements in the new array
for(int i=0;i<input.length;i++){
m.put(input[i], 1);
}
//loop through the given input array and check for missing numbers
for(int i=0;i<a.length;i++){
if (!m.contains(input[i]))
l.add(input[i]);
}
return l;
}
答案 6 :(得分:0)
我希望这个程序对你们大家都有用,我把限制一直到10可以用同样的方式完成,只需用n作为限制并执行相同的操作。
#include <iostream>
#include<math.h>
using namespace std;
int main()
{
int i,x[100],sum1=0,sum2=0,prod1=1,prod2=1,k,j,p=0;
cout<<"Enter 8 elements less than 10, they should be non recurring"<<endl;
for(i=0;i<8;i++)
{
cin>>x[i];
}
sum1=((10)*(11))/2;
for(i=0;i<8;i++)
{
sum2+=x[i];
}
k=sum1-sum2;
for(i=1;i<10;i++)
{
prod1=prod1*i;
}
for(i=0;i<8;i++)
{
prod2=prod2*x[i];
}
j=prod1/prod2;
p=sqrt((k*k)-(4*j));
cout<<"One missing no:"<<p/2<<endl;
cout<<"Second missing no:"<<k-p/2<<endl;
}
答案 7 :(得分:0)
#include <stdio.h>
#include <math.h>
/*
the sum should be 1+...+n = n(n+1)/2
the sum of squares should be 1^2+...+n^2 = n(n+1)(2n+1)/6.
*/
void find_missing_2_numbers(int *arr, int n);
int main()
{
int arr[] = {3,7,1,6,8,5};
find_missing_2_numbers(arr, 8);
return 0;
}
void find_missing_2_numbers(int *arr, int n)
{
int i, size, a, b, sum, sum_of_sqr, a_p_b, as_p_bs, a_i_b, a_m_b;
size = n - 2;
sum = 0;
sum_of_sqr = 0;
for (i = 0; i < size; i++)
{
sum += arr[i];
sum_of_sqr += (arr[i] * arr[i]);
}
a_p_b = (n*(n+1))/2 - sum;
as_p_bs = (n*(n+1)*(2 * n + 1))/6 - sum_of_sqr;
a_i_b = ((a_p_b * a_p_b) - as_p_bs ) / 2;
a_m_b = (int) sqrt((a_p_b * a_p_b) - 4 * a_i_b);
a = (a_p_b + a_m_b) / 2;
b = a_p_b - a;
printf ("A: %d, B: %d\n", a, b);
}
答案 8 :(得分:0)
适用于任何数量的缺失元素: 您可以稍微格式化代码..但它也适用于重复项和非重复项:
public static void main(String args[] ) throws Exception {
Scanner input = new Scanner(System.in);
System.out.println("Enter no. of students in the class");
int N = input.nextInt();
List<Integer> l = new ArrayList<Integer>();
int Nn=N;
System.out.println("Enter the roll numbers");
for(int i=0;i<Nn;i++)
{
int enter=input.nextInt();
l.add(enter);
}
Collections.sort(l);
Integer listarr[]=new Integer[l.size()];
listarr =l.toArray(listarr);
int check=0;
int m1[]=new int[N];
for(int i=0;i<N;i++)
{
m1[i]=i+1;
}
for (int i = 0; i < N; i++) {
boolean flag=false;
{
for (int j = 0; j < listarr.length; j++) {
if(m1[i]==listarr[j])
{
flag=true;
break;
}
else
{
flag=false;
}
}
if(flag==false)
{
System.out.println("Missing number Found : " + m1[i]);
}
}
}
答案 9 :(得分:-1)
public class MissingNumber{
static int[] array = { 1, 3, 5 };
public static void getMissingNumber() {
for (int i = 0; i < array.length; i++)
System.out.println(array[i] + " ");
System.out.println("The Missing Number is:");
int j = 0;
for (int i = 1; i <= 5; i++) {
if (j < array.length && i == array[j])
j++;
else
System.out.println(i + " ");
}
}
public static void main(String[] args) {
getMissingNumber();
}
}
答案 10 :(得分:-1)
@slider答案的代码示例( Java )
/**
* get 2 missed numbers from randomly shuffled array of unique elements from [1,n]
*
* @param array - shuffled array of unique elements from [1,n], but 2 random elements was missed. len = n-2
* @return array with 2 missed elements
*/
public static int[] getMissedNumbers(int[] array) {
int sum = 0;
int fullSum = 0;
int fullProduct = 1;
int product = 1;
for (int i = 0; i < array.length + 2; i++) {
int currNaturalNumber = i + 1;
fullSum = fullSum + currNaturalNumber;
fullProduct = fullProduct * currNaturalNumber;
if (i < array.length) {
sum = sum + array[i];
product = product * array[i];
}
}
int missedSum = fullSum - sum; //firstMissedNum + secondMissedNum
int missedProduct = fullProduct / product; //firstMissedNum * secondMissedNum
//ax*x + bx + c = 0
//x = (-b +- sqrt(b*b - 4*a*c))/2*a
// -b = missedSum , c = missedProduct, a = 1
Double firstMissedNum = (missedSum + Math.sqrt(missedSum * missedSum - 4 * missedProduct)) / 2;
Double secondMissedNum = (missedSum - Math.sqrt(missedSum * missedSum - 4 * missedProduct)) / 2;
return new int[]{firstMissedNum.intValue(), secondMissedNum.intValue()};
}
和用于测试的简单数组生成器
public static Map.Entry<int[], int[]> generateArray(int maxN, int missedNumbersCount) {
int[] initialArr = new int[maxN];
for (int i = 0; i < maxN; i++) {
initialArr[i] = i + 1;
}
shuffleArray(initialArr);
int[] skippedNumbers = Arrays.copyOfRange(initialArr, maxN - missedNumbersCount, maxN);
int[] arrayWithoutSkippedNumbers = Arrays.copyOf(initialArr, maxN - missedNumbersCount);
return new AbstractMap.SimpleEntry<>(arrayWithoutSkippedNumbers, skippedNumbers);
}
private static void shuffleArray(int[] ar) {
Random rnd = ThreadLocalRandom.current();
for (int i = ar.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
答案 11 :(得分:-1)
#include <iostream>
using namespace std;
int main() {
int arr[]={3,1,2,5,7,8};
int n=6;
for(int i=0;i<n;i++){
if(arr[i]>0 && arr[i]<=n){
int temp=arr[i]-1;
if(arr[i]!=arr[temp]){
swap(arr[i],arr[temp]);
i--;
}
}
}
for(int i=0;i<n;i++){
if(arr[i]!=i+1)
cout<<i+1<<endl;
}
// your code goes here
return 0;
}
我们可以使用相同的数组作为存储桶。我们遍历它一次并继续将元素交换到正确的索引。 如果该值小于1或大于数组长度,我们保持原样。 初始阵列 - 3 1 2 5 7 8 掉期(3,5) 5 1 2 3 7 8 掉期(5,8) 8 1 2 3 7 5 在此之后我们再次遍历阵列。没有处于正确位置的元素缺失,因此我们打印索引。 时间复杂度-O(n)