求个能 beats 90% 以上的 Move Zeroes 算法 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
soli
V2EX    程序员

求个能 beats 90% 以上的 Move Zeroes 算法

  •  
  •   soli
    solicomo 2016-07-21 19:15:01 +08:00 4307 次点击
    这是一个创建于 3383 天前的主题,其中的信息可能已经有所发展或是发生改变。

    题目: https://leetcode.com/problems/move-zeroes/

    开始自己实现了一个,但需要 20ms ,只能 beats 27.02%。

    然后去论坛中看了好几个实现,有些号称能 beats 95% , 但我照着实现、提交后仍然只能 20ms , beats 27.02%。

    论坛中的实现、我的实现都和编辑推荐的算法一样。

    语言选的是 C++ 。

    附我的实现:

    class Solution { public: void moveZeroes(vector<int>& nums) { int i = 0; int l = nums.size(); while (nums[i] != 0 && i < l) ++i; for (int j = i + 1; j < l; ++j) { if (nums[j] != 0) { nums[i++] = nums[j]; } } while(i < l) nums[i++] = 0; } }; 
    29 条回复    2016-09-22 19:45:27 +08:00
    yongzhong
        1
    yongzhong  
       2016-07-21 19:21:53 +08:00
    号称 95 的一般都是很早以前提交的,其他人拿他的答案刷一刷,比率就降下来了
    soli
        2
    soli  
    OP
       2016-07-21 22:28:25 +08:00
    @yongzhong 但是我改了一版和他的一样的,还是 27% 哈。所以,我觉得应该有更好的。
    breeswish
        3
    breeswish  
       2016-07-21 22:34:32 +08:00   1
    算法不复杂,所以时间太短,不稳定因素比较多导致测量不准确
    不信你多交几遍同样的代码,可能就某次刷到前 10%了
    mengzhuo
        4
    mengzhuo  
       2016-07-22 00:20:33 +08:00
    呃……为啥你有三个循环
    明明一个就成了啊
    Valyrian
        5
    Valyrian  
       2016-07-22 05:43:01 +08:00   1
    20ms...
    这点时间能说明啥。。误差都比这个长
    yaoyuan7571
        6
    a href="/member/yaoyuan7571" class="dark">yaoyuan7571  
       2016-07-22 10:18:03 +08:00   1
    void moveZeroes(vector<int>& nums) {
    int zero_count=0;
    for (int i=0; i<nums.size(); i++) {
    if (nums[i] == 0) {
    zero_count++;
    } else {
    int j=i-zero_count;
    nums[j] = nums[i];
    }
    }
    int last = nums.size()-1;
    for (int i=0;i<zero_count;i++) {
    nums[last]=0;
    last--;
    }
    }
    soli
        7
    soli  
    OP
       2016-07-22 12:09:12 +08:00
    @mengzhuo 一个循环的话,会多几次没用的赋值或判断。并且,那个号称 beats 95% 的和这个逻辑一样。

    我也试过用一个循环的,也是 20ms 。
    flyingghost
        8
    flyingghost  
       2016-07-22 12:12:08 +08:00
    哪里参加 beat ?

    我执行时间是 0ms 。

    ```java
    public class Solution {
    public void moveZeroes(int[] nums) {
    int empty=0;
    int start=0;
    for(int i=0;i<nums.length;i++){
    if(nums[i]==0){
    empty++;
    }
    else{
    if(empty==0){
    start=i+1;
    }
    else{
    nums[start]=nums[i];
    nums[i]=0;
    start++;
    }
    }
    }
    }
    }
    ```
    flyingghost
        9
    flyingghost  
       2016-07-22 12:14:43 +08:00
    。。。不是说好了支持 markdown 的吗?
    soli
        10
    soli  
    OP
       2016-07-22 12:16:11 +08:00
    @yaoyuan7571 太神奇了!这个能 beats 94.91% !

    多谢多谢。

    我去研究一下这个为啥快。
    soli
        11
    soli  
    OP
       2016-07-22 12:18:36 +08:00
    @flyingghost 说来奇怪,很多这种算法题,用 Java 反而测出来的性能更高。

    Java > C++ > C 。。。很无语

    提交之后去看『 Submission Details 』,那里有个图表可以看到 beats ,还可以在各种语言之间比较。
    soli
        12
    soli  
    OP
       2016-07-22 12:29:08 +08:00
    @breeswish 我擦!真坑啊!果然是误差!

    我连续提交了几次相同的代码,每结果都不一样!终于有一次刷到了 16 ms beats 94.91%!

    我又刷了一次上面那位仁兄 @yaoyuan7571 的代码,时间也变了,变成 22ms beats 22.41% 了。

    郁闷了好几天,深深地了怀疑自己的智商。。。
    soli
        13
    soli  
    OP
       2016-07-22 12:33:29 +08:00
    @Valyrian 确实是误差!

    原以为『多次测量求平均值』是大家公认的常识呢。谁知道 LeetCode 这么坑。。。

    或者用台差点的机器,再把测试用例搞的量大一点,也能降低误差吧。
    mengzhuo
        14
    mengzhuo  
       2016-07-22 13:51:11 +08:00 via iPhone
    @soli 不太清楚 C++
    但是 in place 对比哪里来赋值?
    mengzhuo
        15
    mengzhuo  
       2016-07-22 13:56:26 +08:00 via iPhone
    而且都是 O(n)怎么可能有这么大差异?
    lawlietxxl
        16
    lawlietxxl  
       2016-07-22 14:04:12 +08:00
    12 行 solution

    public class Solution {
    public void moveZeroes(int[] nums) {
    if(nums.length < 2)
    return;
    int idx = 0;
    for(int n:nums)
    if(n != 0)
    nums[idx++] = n;
    while(idx < nums.length)
    nums[idx++] = 0;
    }
    }
    fcicq
        17
    fcicq  
       2016-07-22 14:06:37 +08:00
    online judge 也就会用 time 计数. perf 等方法他们不会. 误差太正常.
    pathletboy
        18
    pathletboy  
       2016-07-22 14:43:02 +08:00   1
    懒汉版
    class Solution {
    public:
    static int compvar(const void *one, const void *two) {
    return *(int*)One==0;
    }

    void moveZeroes(vector<int>& nums) {
    qsort(&nums[0], nums.size(), sizeof(int), compvar);
    }
    };
    YORYOR
        19
    YORYOR  
       2016-07-22 18:00:50 +08:00
    YORYOR
        20
    YORYOR  
       2016-07-22 18:01:48 +08:00
    java 这竞争。。
    SuperFashi
        21
    SuperFashi  
       2016-07-22 18:52:34 +08:00 via Android
    这误差就是评测机的玄学,像我们这种打 oi 的就得祈祷评测机不出差错,上次写了个博弈论的记忆化搜索,基本上都在 960-990ms 之间,我运气差,交了好几遍都是 1.006s ,一怒之下刷了 5 次,终于不 tle 了。

    而且 leetcode 上 java 比 c++快,不高兴。

    但是我想吐槽一下两位:
    @yaoyuan7571 为啥不用迭代器呢……
    @pathletboy ……为啥要用 c 的 qsort 和排序函数写法, c++本来就是为了避免各种指针的使用的啊……
    DaCong
        22
    DaCong  
       2016-07-22 20:22:37 +08:00
    @flyingghost 评论不支持 markdown ,只有帖子正文支持
    yhylord
        23
    yhylord  
       2016-07-22 20:43:58 +08:00
    @SuperFashi 确实 C++11 的话写迭代器用 auto 就行了巨爽,但是更早的要手动写长长的 vector<int>::iterator 还是挺烦的
    skydiver
        24
    skydiver  
       2016-07-22 22:55:11 +08:00
    class Solution {
    public:
    void moveZeroes(std::vector<int> &nums) {
    std::stable_partition(nums.begin(), nums.end(),
    [](int a) { return a != 0;});
    }
    };

    最简单的写法……可惜还是 20ms
    jeffersonpig
        25
    jeffersonpig  
       2016-07-23 18:10:43 +08:00
    leetcode 的性能数据没个准头的
    breeswish
        26
    breeswish  
       2016-07-24 15:41:10 +08:00
    @soli 这个其实没法儿准确测量,撞上时间片调度一下就 10ms 加上去了…

    以及各种 OJ 目标并不是准确测量耗时,而是衡量你编写算法的对错,因而只测「答案是否正确」、「是否在指定时间内结束(即算法时间复杂度是否满足需求)」、「资源占用是否在指定空间内(空间复杂度是否满足需求)」,是不会多次运行测量准确时间的,这没意义。
    soli
        27
    soli  
    OP
       2016-07-25 11:23:51 +08:00
    @breeswish 前几题都改好几次,直到改到 beats 90%+ 才算完。还蛮有成就感的。

    自从知道这个时间是骗人的,就没动力继续刷了。。。
    laobubu
        28
    laobubu  
       2016-09-21 21:20:27 +08:00
    https://ooo.0o0.ooo/2016/09/21/57e288f2d12d3.png

    虽然是 C++,但是还是用 C 的方式写了一个,突然感觉碉堡了……
    soli
        29
    soli  
    OP
       2016-09-22 19:45:27 +08:00
    @laobubu 66666666666
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2610 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 14:48 PVG 22:48 LAX 07:48 JFK 10:48
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86