• leetcode day2


    【参考】http://book.2cto.com/201210/5663.html

    【参考】http://www.cnblogs.com/exponent/articles/2141477.html

    nim game定义【292】:

    Nim是一种两个人玩的游戏,玩家双方面对一堆硬币(或者石头或者豆粒)。假设有k≥1堆硬币,每分别有n1,n2,…,nk枚硬币。这一游戏的目标就是取得最后一枚硬币。游戏的规则如下:

    (1)玩家轮番出场(我们称第一个取子的玩家为Ⅰ,而第二个玩家为Ⅱ)。

    (2)当轮到一个玩家取子时,他们都要从选择的硬币堆中至少取走一枚硬币。(这位玩家也可以把所选硬币堆的硬币都取走,于是剩下一个空堆,这时它“退出”。)

    当所有硬币堆都空了的时候,游戏结束。走最后一步的玩家,即取走最后一枚硬币的玩家获胜。

    在这个游戏中的变量是堆数k和堆中的硬币数n1,n2,…,nk。我们要问的组合问题是确定是第一个玩家胜还是第二个玩家胜1,以及这位玩家为了获胜应该如何取子,也就是获胜策略。

    为了进一步理解Nim游戏,下面我们考虑一些特殊的情况2。如果一开始就只有一堆硬币。那么玩家Ⅰ取走所有硬币就可以获胜。现在假设k=2,且分别有n1枚和n2枚硬币。玩家Ⅰ是否可以获胜不取决于n1,n2具体是多少,而是取决于它们是否相等。假设n1≠n2。玩家Ⅰ可以从大堆中取走足够多的硬币以便对于玩家Ⅱ来说,剩余两堆的大小相同。现在,当轮到玩家Ⅰ时,他可以模仿玩家Ⅱ的取子方式。因此,如果玩家Ⅱ从一堆中取走了c枚,那么玩家Ⅰ则从另一堆中取走相同数目的硬币。这样的策略保证玩家Ⅰ可以获胜。如果n1=n2,那么玩家Ⅱ通过模仿玩家Ⅰ的取子方式而获胜。因此,我们就完全解决了2堆的Nim游戏的取子问题。下面是2堆Nim游戏的一个例子,其堆的大小分别是8和5:

    上述解决2堆Nim游戏的想法是用某种方式取子使得剩余两堆的大小相同,这一想法可以推广到任意k堆的情况。

    把nim每堆的数字用二进制表示,然后位数对齐进行异或运算,如果全0则说明是game是平衡的,否则是非平衡的。

    若一个Nim游戏不是平衡的,则称它为非平衡的(unbalanced)。我们说第i位是平衡的,指的是和ai+bi+…+ei是偶数,否则就是非平衡的。因此,若一个游戏是平衡的,则它在各个位上都是平衡的,而对于非平衡游戏来说,至少存在一个非平衡位。

    于是我们有下面的陈述:

    玩家Ⅰ(先出手的)能够在非平衡Nim游戏中获胜,而玩家Ⅱ(后出手的)则能够在平衡Nim游戏中获胜。

    为了理解上述的结论,我们扩展2堆Nim游戏中使用的策略。假设这个Nim游戏是非平衡的。设最大不平衡位是第j位。于是,玩家Ⅰ以某种方式取走硬币给玩家Ⅱ留下一个平衡游戏。他的作法是:选出一个第j位上是1的堆,并从中取走一定数目的硬币使得剩下的游戏是平衡的(参见练习题32)。无论玩家Ⅱ怎样做,他都不得不又给玩家Ⅰ留下一个不平衡的游戏,玩家Ⅰ又把这个游戏变成平衡游戏。如此这般继续下去就可以保证玩家Ⅰ获胜。如果这个游戏开始时就是平衡游戏,那么玩家Ⅰ第一次取子使其变成不平衡游戏,此时轮到玩家Ⅱ采用平衡游戏的策略。

    下面应用此获胜策略来考虑4-堆的Nim取子游戏。其中各堆的大小分别为7,9,12,15枚硬币。用二进制表示各数分别为:0111,1001,1100和1111。于是可得到如下一表:
     

    23 = 8

    22 = 4

    21 = 2

    20 = 1

    大小为7的堆
    0
    1
    1
    1
    大小为9的堆
    1
    0
    0
    1
    大小为12的堆
    1
    1
    0
    0
    大小为15的堆
    1
    1
    1
    1
    由Nim取子游戏的平衡条件可知,此游戏是一个非平衡状态的取子游戏,因此,游戏人I在按获胜策略进行取子游戏下将一定能够取得最终的胜利。具体做法有多种,游戏人I可以从大小为12的堆中取走11枚硬币,使得游戏达到平衡(如下表),
     

    23 = 8

    22 = 4

    21 = 2

    20 = 1

    大小为7的堆
    0
    1
    1
    1
    大小为9的堆
    1
    0
    0
    1
    大小为12的堆
    0
    0
    0
    1
    大小为15的堆
    1
    1
    1
    1
    之后,无论游戏人II如何取子,游戏人I在取子后仍使得游戏达到平衡。
    同样的道理,游戏人I也可以选择大小为9的堆并取走5枚硬币而剩下4枚,或者,游戏人I从大小为15的堆中取走13枚而留下2枚。

    归根结底,Nim取子游戏的关键在于游戏开始时游戏处于何种状态(平衡或非平衡)和第一个游戏人是否能够按照取子游戏的获胜策略来进行游戏。

    leetcode上的nim游戏是只有一堆硬币,并且每次取硬币的个数(小于等于3个,至少1个)有限制的特殊情况,

    public boolean canWinNim(int n) {
        if (n <= 0) {return false;}
        return n % 4 != 0;
    }

     explanation:


    • According to the hint, we know that if n = 4, no matter how many stones I remove, I lose. If n = 5, I can remove one stone and there are 4 stones for another player. Thus, I win. Similarly, if n = 6 or 7, I can remove 2 or 3 stones and i win finally.
    • If n = 8, no matter how many stones I remove, there are 7 or 6 or 5 stones for another player, s/he can remove stones as we said before and then wins.
    • If n = 9 or 10 or 11, I can leave 8 stones to another player, then I win.
    • If n = 12, I can leave 9, 10 or 11 stones to another player. Then, s/he can leave 8 stones to me, then I lose. ......
    • The rule is: if (n % 4 == 0) then I lose.

    Add Digits【258】:

    Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.

    For example:

    Given num = 38, the process is like: 3 + 8 = 111 + 1 = 2. Since 2 has only one digit, return it.

    Could you do it without any loop/recursion in O(1) runtime?

    维基百科:一个整数数字和,是把它的所有数字相加起来所得的和。例如,84001的数字和是8+4+0+0+1 = 13。

    这个概念与数字根有密切的关系,但并不相同,数字根是把所有数字相加起来所得的和,然后再把这个和的所有数字相加起来,又得到一个和,重复这个步骤,直到最终只剩下一个数字,这个数字便称为数字根。数字和可以是任意的值,而数字根只能是1到9。

    解题思路:数字根是有规律的,因为数字跟是不大于9的,所以可以通过求9的余数,即可得到数字跟。题目要求不用循环,时间复杂度为常数

    public class Solution {
        public int addDigits(int num) {
            if(num==0)return num;
            else return num%9==0?9:num%9;
           /*下面的方法时间不符合要求,执行了14ms
            if(num<10){
                return num;
            }
           while(num>10){
               String aS = String.valueOf(num);
               char[] asC = aS.toCharArray();
               for(int i=0;i<asC.length;i++){
                 num+=asC[i];
               } 
           } 
           return num;*/
        }
    }

    Maximum Depth of Binary Tree【104】:

    Given a binary tree, find its maximum depth.

    思路:使用递归,给一个节点,如果还有子节点,则深度加1

    public class Solution {
        public int maxDepth(TreeNode root) {
    //注意root的判空,还有当只有一个节点的时候,返回的数值应该是1,所以注意加1
            return (root == null)?0:Math.max(1+maxDepth(root.left),1+maxDepth(root.right));
        }
    }

    【237】Delete Node in a Linked List

    Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.

    Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with value 3, the linked list should become 1 -> 2 -> 4 after calling your function.

    思路:这是个单链表,给了要删除的结点,既然我们无法拿到他的前驱结点,不能按照一般的的方法删除结点,所以就让要删除的结点变成下一个结点,然后把下一个结点删除了

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    public class Solution {
        public void deleteNode(ListNode node) {
            if(node==null)return;
            else if(node.next==null)return;
            else{
                node.val = node.next.val;
                node.next = node.next.next; 
            }
            
        }
    }
  • 相关阅读:
    求CRC校验和的低位和高位的两种方式
    求数组的长度 C
    C语言判断文件是否存在(转)
    Android使用JNI实现Java与C之间传递数据(转)
    字节流、字符串、16进制字符串转换__Java(转)
    字符串参数传递与返回值(转)
    JNI数据类型(转)
    十进制的数转换成十六进制的数 (转)
    C语言字符串长度(转)
    字符串截取函数--C语言(转)
  • 原文地址:https://www.cnblogs.com/lucky-star-star/p/4951478.html
Copyright © 2020-2023  润新知