智力题

作者: 一酷到底 | 来源:发表于2019-05-14 09:35 被阅读0次

    我能赢吗

    输入:
    maxChoosableInteger = 10
    desiredTotal = 11
    输出:
    false
    思路:我们首先来看如果给定的数字范围大于等于目标值的话,直接返回true。如果给定的数字总和小于目标值的话,说明谁也没法赢,返回false。然后我们进入递归函数,首先我们查找当前情况是否在哈希表中存在,有的话直接返回即可。我们使用一个整型数按位来记录数组中的某个数字是否使用过,我们遍历所有数字,将该数字对应的mask算出来,如果其和used相与为0的话,说明该数字没有使用过,我们看如果此时的目标值小于等于当前数字,说明已经赢了,或者我们调用递归函数,如果返回false,说明也是第一个人赢了。为啥呢,因为当前我们已经选过数字了,此时就该对第二个人调用递归函数,只有他的结果是false,我们才能赢,所以此时我们标记true,返回true。如果遍历完所有数字,我们标记false,返回false

    class Solution {
    public:
        bool canIWin(int maxChoosableInteger, int desiredTotal) {
            if (maxChoosableInteger >= desiredTotal) return true;
            if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) return false;
            unordered_map<int, bool> m;
            return canWin(maxChoosableInteger, desiredTotal, 0, m);
        }
        bool canWin(int length, int total, int used, unordered_map<int, bool>& m) {
            if (m.count(used)) return m[used];
            for (int i = 0; i < length; ++i) {
                int cur = (1 << i);   //表示将1左移i位,1,2,4,8...
                if ((cur & used) == 0) {
                    if (total <= i + 1 || !canWin(length, total - (i + 1), cur | used, m)) {
                        m[used] = true;
                        return true;
                    }
                }
            }
            m[used] = false;
            return false;
        }
    };
    

    猜数字大小(https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii/)

    从1-n中选一个数,n = 10, 我选择了8.
    第一轮: 你猜我选择的数字是5,我会告诉你,我的数字更大一些,然后你需要支付5块。
    第二轮: 你猜是7,我告诉你,我的数字更大一些,你支付7块。
    第三轮: 你猜是9,我告诉你,我的数字更小一些,你支付9块。
    游戏结束。8 就是我选的数字。
    你最终要支付 5 + 7 + 9 = 21 块钱。
    给定 n ≥ 1,计算你至少需要拥有多少现金才能确保你能赢得这个游戏。
    思路
    dp[i][j]表示从[i,j]中猜出正确数字所需要的最少花费金额.(dp[i][i] = 0)
    假设在范围[i,j]中选择x, 则选择x的最少花费金额为: max(dp[i][x-1], dp[x+1][j]) + x
    用max的原因是我们要计算最坏反馈情况下的最少花费金额(选了x之后, 正确数字落在花费更高的那侧)

        初始化为(n+2)*(n+2)数组的原因: 处理边界情况更加容易, 例如对于求解dp[1][n]时x如果等于1, 需要考虑dp[0][1](0不可能出现, dp[0][n]为0)
        而当x等于n时, 需要考虑dp[n+1][n+1](n+1也不可能出现, dp[n+1][n+1]为0)
        
        如何写出相应的代码更新dp矩阵, 递推式dp[i][j] = max(max(dp[i][x-1], dp[x+1][j]) + x), x~[i:j], 可以画出矩阵图协助理解, 可以发现
        dp[i][x-1]始终在dp[i][j]的左部, dp[x+1][j]始终在dp[i][j]的下部, 所以更新dp矩阵时i的次序应当遵循bottom到top的规则, j则相反, 由于
        i肯定小于等于j, 所以我们只需要遍历更新矩阵的一半即可(下半矩阵)
    
      public int getMoneyAmount(int n) {
            int[][] dp = new int[n+2][n+2];
            for(int i = n; i >= 1; --i) {
                for(int j = i; j <= n; ++j) {
                    if(i == j)
                        dp[i][j] = 0;
                    else {
                        dp[i][j] = Integer.MAX_VALUE;
                        for(int x = i; x <= j; ++x) 
                            dp[i][j] = Math.min(dp[i][j], Math.max(dp[i][x-1], dp[x+1][j]) + x);   //为什么这个地方最外面是Math.min???
                    }
                }
            }
            return dp[1][n];
        }
    

    nim游戏

    你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。
    你们是聪明人,每一步都是最优解。 编写一个函数,来判断你是否可以在给定石头数量的情况下赢得游戏。

    示例:
    输入: 4
    输出: false
    解释: 如果堆中有 4 块石头,那么你永远不会赢得比赛;
    因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。

      bool canWinNim(int n) {
            return n%4==0?false:true;
        }
    

    变态跳台阶

    一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

    f(1)=1, f(2)=2, f(3)=4, f(4)=8 设n+1级f(n+1),有
    f(n+1) = f(1) + f(2) + ... + f(n)
    f(n+2) = f(1) + f(2) + ... + f(n+1)
    f(n+2)= 2f(1) + 2f(2) + ... + 2f(n)
    故得f(n+2) = 2f(n+1)
    

    矩形覆盖

    我们可以用 2 * 1 的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2 * 1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
    f(1) = 1
    f(2) = 2
    f(n) = f(n-1) + f(n-2)

    孩子们的游戏

    有n个数,从0开始编号,每次删除第m个数,下一轮循环从m+1开始。求最后剩下的数字是多少
    虽然有递推公式,但是用链表模拟更好

    public int LastRemaining_Solution(int n, int m) {
            LinkedList<Integer> list = new LinkedList<>();
            for(int i=0;i<n;i++)
                list.add(i);
            int a = 0;
            while(list.size() > 1)
            {
                a = (a+m-1) % list.size();
                list.remove(a);//每次删除,直到留下最后的那一个!
            }
            if(list.size() == 1)
                return list.get(0);//数组只剩下最后的一个
            return -1;
        }
    

    n!末尾有多少个0

    思路:5!=54321,0的个数和5的个数相等0

    相关文章

      网友评论

          本文标题:智力题

          本文链接:https://www.haomeiwen.com/subject/apyjaqtx.html