【本文链接】

http://www.cnblogs.com/hellogiser/p/find-k-missing-numbers-from-1-to-n.html

 【题目】

从1到n,共有n个数字(无序排列),每个数字只出现一次。现在随机拿走一个数字x,请给出最快的方法,找到这个数字。要求时间复杂度为O(n),空间复杂度为O(1)。如果随机拿走k(k>=2)个数字呢?

【分析】

题目给出的条件很强,数字是从1~n的数字,限制了数字的范围;每个数字只出现一次,限制了数字出现的次数;随即拿走了一个数字,说明只有一处是与其他不同、不符合规律的。我们可以利用这些特点来选择合适的解法。

(1)Hash法。利用Hash法统计数字出现的次数,次数为0的即为所求。时间复杂度O(n),空间复杂度O(n)。通常这不是面试、笔试时想要的答案,但是Hash的优势在于其通用性。

(2)排序法。利用快排,得到排序后的数组,然后顺序遍历,统计次数为0的数字。时间复杂度O(nlgn),空间复杂度O(1)。其时间复杂度略高,通常也不是面试官期待的解法,但排序法也算是一种通用做法。

(3)元素相乘/相加法。时间复杂度O(n),空间复杂度O(1)。

元素相乘法:由于只有一个元素被拿走,因此我们只需要先算出n的阶乘n!,再除以现存所有数字的乘积M,即可得到拿走的数字x (x=n!/M)。但是且缺陷是n不能太大,否则会溢出。

元素相加法:先算出从1到n的所有数字的和Sn,然后减去现有所有数字的和sum,即可得到拿走的数字x(x=Sn-sum)。元素相加法比元素相乘要更好一些。

(4)位运算。时间复杂度O(n),空间复杂度O(1)。

位运算法如果可以使用的话,应该是计算最快的方法。但是位运算对条件要求也较苛刻,一般需要元素有特殊规律,才有可能使用这种方法。在本题目中,对1~n所有元素进行xor运算得到A=1^2^3^…^(x-1)^x^(x+1)^…^n,在对取走一个元素后剩下的元素进行xor运算得到B=1^2^3^…^(x-1)^(x+1)^…^n,二者xor即可得拿走的数字x = A^B。因为在A^B的过程中相同的数字都被抵消掉了,剩余的结果即为x。

【代码】

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
 
// 61_FindMissingNumberFrom1toN.cpp : Defines the entry point for the console application.
//
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/5/28
*/

#include "stdafx.h"

/*
A=1^2^3^...^(x-1)^x^(x+1)^...^n
B=1^2^3^...^(x-1)^(x+1)^...^n
x = A^B

n=9
1,2,3,4,6,7,8,9
x = 5
*/
int FindMissingNumberFrom1ToN(int data[], int n)
{
    ;
    )
        ;
    // xor all
;
    ; i <= n; i++)
        xor_all ^= i;

// xor of current array
;
    ; i < length; i++)
        xor_current ^= data[i];

//get result
    int result = xor_all ^ xor_current;
    return result;
}

void test_base(int data[], int n)
{
    int result = FindMissingNumberFrom1ToN(data, n);
    printf("%d \n", result);
}

void test_case1()
{
    };
    int length = sizeof(data) / sizeof(int);
    test_base(data, length + );
}

void test_case2()
{
    };
    int length = sizeof(data) / sizeof(int);
    test_base(data, length + );
}

void test_case3()
{
    };
    int length = sizeof(data) / sizeof(int);
    test_base(data, length + );
}

void test_main()
{
    test_case1();
    test_case2();
    test_case3();
}

int _tmain(int argc, _TCHAR *argv[])
{
    test_main();
    ;
}
/*
4
1
5
*/

【扩展】

如果随机拿走两个数字呢?如果随机拿走k(k>2)个数字呢?

(1)(2)是通用做法,仍适合。

(3)扩展:

K=1时,构造2个等式。

Sa = 1+2+…(x-1)+x+(x+1)…+n

Sb = 1+2+…(x-1)+(x+1)…+n

X = Sa-Sb

K=2时,构造4个等式。

S2a = 12+22+…+x2+…+y2+…+n

S2b = 12+22+…(x-1)2+(x+1)2…+(y-1)2+(y+1)2…+n

S1a = 1+2+…+x+…+y+…+n

S1b = 1+2+…(x-1)+(x+1)…+(y-1)+(y+1)…+n

则有x2+y2=S2a-S2b,x+y =S1a-S1b。可以求解得到x和y。

同理(k>2),构造2*k个等式,可以得到关于k个数的k个方程,求解即可得到k个数字。

(4)扩展:

思考一下,如何扩展?

【参考】

http://ouscn.diandian.com/post/2013-10-06/40052170552

【本文链接】

http://www.cnblogs.com/hellogiser/p/find-k-missing-numbers-from-1-to-n.html

61. 从1到n,共有n个数字,每个数字只出现一次。从中随机拿走一个数字x,请给出最快的方法,找到这个数字。如果随机拿走k(k>=2)个数字呢?[find k missing numbers from 1 to n]的更多相关文章

  1. 给定两个字符串 s 和 t,它们只包含小写字母。 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。

    给定两个字符串 s 和 t,它们只包含小写字母.字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母.请找出在 t 中被添加的字母. 示例: 输入: s = "abcd" ...

  2. 现在有一个长度20的SET,其中每个对象的内容是随机生成的字符串,请写出遍历删除LIST里面字符串含"2"的对象的代码。

    现在有一个长度20的SET,其中每个对象的内容是随机生成的字符串,请写出遍历删除LIST里面字符串含"2"的对象的代码. public class RemoveTwo { //le ...

  3. 谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。

    谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数. Google2009华南地 ...

  4. 代码题(3)— 最小的k个数、数组中的第K个最大元素、前K个高频元素

    1.题目:输入n个整数,找出其中最小的K个数. 例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4. 快排思路(掌握): class Solution { public ...

  5. 算法导论学习之线性时间求第k小元素+堆思想求前k大元素

    对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...

  6. [LeetCode] All Nodes Distance K in Binary Tree 二叉树距离为K的所有结点

    We are given a binary tree (with root node root), a target node, and an integer value K. Return a li ...

  7. [Swift]LeetCode698. 划分为k个相等的子集 | Partition to K Equal Sum Subsets

    Given an array of integers nums and a positive integer k, find whether it's possible to divide this ...

  8. LeetCode竞赛题:K 次取反后最大化的数组和(给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次。)

    给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次.(我们可以多次选择同一个索引 i.) 以这种方式修改数组后 ...

  9. hdu6003 Problem Buyer 贪心 给定n个区间,以及m个数,求从n个区间中任意选k个区间,满足m个数都能在k个区间中找到一个包含它的区间,如果一个区间包含了x,那么 该区间不能再去包含另一个数,即k>=m。求最小的k。如果不存在这样的k,输出“IMPOSSIBLE!”。

    /** 题目:hdu6003 Problem Buyer 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6003 题意:给定n个区间,以及m个数,求从n个区 ...

随机推荐

  1. Java 并发-访问量

    有几个常用的措施 1.对常用功能建立缓存模块 .尽量使用缓存,包括用户缓存,信息缓存等,多花点内存来做缓存,可以大量减少与数据库的交互,提高性能.统计的功能尽量做缓存,或按每天一统计或定时统计相关报表 ...

  2. Shell编程中Shift的用法

    Shell编程中Shift的用法 位置参数可以用shift命令左移.比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1.$2.$3丢弃,$0不移动.不带参数的shif ...

  3. ThinkPHP多表联合查询的常用方法

    1.原生查询示例: $Model = new Model(); $sql = 'select a.id,a.title,b.content from think_test1 as a, think_t ...

  4. 【转】Eclipse下导入外部jar包的3种方式

    我们在用Eclipse开发程序的时候,经常要用到第三方jar包.引入jar包不是一个小问题,由于jar包位置不清楚,而浪费时间.下面配图说明3种Eclipse引入jar包的方式.   1.最常用的普通 ...

  5. HDU 4901 The Romantic Hero

    The Romantic Hero Time Limit: 3000MS   Memory Limit: 131072KB   64bit IO Format: %I64d & %I64u D ...

  6. groovy-实现接口

    Groovy提供了一些非常方便的方法来实现接口 使用闭包实现接口 只有一个方法的接口可以使用闭包来实现,例如 1 // a readable puts chars into a CharBuffer ...

  7. HDU 2255 奔小康发大财

    传送门 Solution: KM算法 关于KM算法有一篇极好的文档http://www.cse.ust.hk/~golin/COMP572/Notes/Matching.pdf Implementat ...

  8. JQueryEasyUI datagrid框架的基本使用

    http://www.jb51.net/article/35348.htm 今天说说这个datagrid框架的基本使用,这个框架一直以来都是大家比较头疼的框架,尤其是Json数据的拼接,后台前台都很重 ...

  9. 提示用户一直输入数字(默认为正整数),当用户输入end的时候显示当前输入数字中的最大值。

    string input = ""; ; while (input != "end") { Console.WriteLine("请输入一个正整数,输 ...

  10. Canvas与Image互转

    function fImageToCanvas(image){ var oCanvas = document.createElement("canvas"); oCanvas.wi ...