• [笔试题] 两个有趣的问题


    • 有n瓶粉末,一瓶有毒。有毒的粉末融在水里一小时后水会变蓝。你有一些试管,问最少须要多少时间和多少试管就能确定毒粉末呢?不考虑粉末导入试管的时间。

    这道题最主要的想法就是时间换空间或者空间换时间,即n个试管用1小时的时间,或者1个试管用n小时依次试验过来。在实际生产中应该偏向于空间换时间,由于硬性资源能够添加。而程序假设找不到好的优化方法执行时间基本也就定了,所以时间比空间重要的多。可是这两个显然都不是什么好办法。另外一个比較好的解决的方法就是二分,把瓶子分两组。花一个小时排除掉一半的瓶子。再花一个小时排除剩下中一半的瓶子....由于每个小时后的溶液都已验证过。能够倒掉,所以试管可反复利用,所以结果就是1支试管。log2(N)向上取整的时间。可是长时间的等待显然是不行的。还不如牺牲空间来节省时间。所以我们也能够三分四分或者N分来加速推断,仅仅只是依照这样的程度分下去,最后就变成了n-1个试管和1小时的时间......

    初看这道题没什么特别好的想法,后来还是想出了个绝妙的办法:仅仅须要1个小时。而且仅仅须要log(N+1)向上取整的试管数量。这样时间已经是最短时间,而且空间也应该是最小空间

    全部瓶子从1~n编号。摆上log(N+1)向上取整数量的试管,从右至左代表二进制的低位到高位,全部粉末编号转化成二进制,分别倒进对应的试管里。一个小时以后,变蓝试管为1,未变蓝试管为0,这个二进制序列转成10进制就是毒粉末的编号了。比方10瓶粉末,发现第2和第3支试管变蓝。即0110,显然6号瓶就是毒粉末了。这个方法好像还能继续优化,之前考虑编号从1開始是由于认为全部粉末都应该參与实验。好像不是必需。

    编号能够从0開始。假设试管一个都没蓝。那么未參与的0号瓶就是毒瓶了,这样有时候又能省下一支试管。

    所以终于答案:1小时的时间。log(N)向上取整的试管数量。即N-1的二进制位数。

    1000瓶粉末也仅仅须要10支试管和1小时即可了~


    • 给定一个无环的单链表,怎样高速定位位于链表中间的那个节点?返回值为指向中间节点的指针。

    先来看看朴素的算法:首先须要遍历一遍整个链表,计算出节点数量N。然后再次遍历链表N/2次,这样就找出位于中间的结点了。这样就是O(N)的时间复杂度了。附带一个整形变量表示N。

    指针移动N+N/2次,第一次遍历时整形变量++N次。

    我想到了个更好的办法:仅仅需两个指针,仅仅遍历一次即可了。

    两个指针一開始先指向头,然后第一个指针每次走两步,第二个指针每次走一步,由于无环,当第一个指针走到末尾的时候,第二个指针自然就在中间了。

    PS:以下是我写的比較简洁的代码,有更简洁的吗?

    node* find(node *head)
    {
        node *s = head, *t = head;
        while(t = t->next)
        {
            s = s->next;
            if((t = t->next) == NULL) break;
        }
        return s;
    }

    完整測试代码例如以下:

    #include<iostream>
    
    using namespace std;
    
    struct node
    {
        int val;
        node* next;
    };
    
    void CreateLinkList(node *LinkList)
    {
        node *s = LinkList;
        for(int i = 0; i < 10; i++)
        {
            node *t = new node;
            t->val = i;
            t->next = NULL;
            s = s->next = t;
        }
    }
    
    void ShowLinkList(node * LinkList)
    {
        node *s = LinkList->next;
        while(s = s->next)
            printf("%d ", s->val);
        putchar(10);
    }
    
    node* find(node *head)
    {
        node *s = head, *t = head;
        while(t = t->next)
        {
            s = s->next;
            if((t = t->next) == NULL) break;
        }
        return s;
    }
    
    int main()
    {
        node *LinkList = new node;
        CreateLinkList(LinkList);
        ShowLinkList(LinkList);
    
        node *re = find(LinkList->next); // 传入的參数是第一个有效节点
        printf("mid:%d
    ", re->val);
        
        getchar();
        return 0;
    }


  • 相关阅读:
    Drozer渗透测试工具(使用篇)
    Teamcenter中TCComponentItem与TCComponentBOMLine的创建
    Swing中分割面板JSplitPane的使用
    Swing中菜单栏JToolBar的使用
    Javaweb项目导出成jar包并使用Windows定时任务定时执行
    TCSOA获取BOMLine
    SQLite Expert安装与注册
    获取分类节点
    处理TC的Command问题
    通过TCComponentBomLine获取ItemRevision的两种情况
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7085755.html
Copyright © 2020-2023  润新知