Leetcode Brainteaser类(292 319 777) 题解

292题:Nim Game    

不难看出递推式:


num[i]表示有i个石子时能不能赢。堆中有i个石子时,赢的条件是i-1、i-2和i-3个石子有一种不能赢,即能找到一种对方失败的拿法即可。

纸上写几个就会发现结果的周期为4,是4的倍数就会输,其他都能赢。

所以写出程序。

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


319题:Bulb Switcher    

手推几个,发现第i个灯最后的开关取决于i在[2 - i / 2]中因数的个数是奇数还是偶数。

于是采用筛选法求素数的思想,从2~i / 2把它的倍数都打上标记,结果发现超时,代码如下:

int bulbSwitch(int n) {
    bool* num = new bool[n + 1]();
    num[1] = 1;
    for (int i = 2; i <= n / 2; i++) {
        int c = i + i;
        while (c <= n) {
            num[c] = !num[c];
            c += i;
        }
    }
    int res = 0;
    for (int i = 1; i <= n; i++) {
        if (num[i])
            res++;
    }
    return res;
}

因此O(N)的算法是行不通的,那只能再找规律了。再手推几个,发现如果[2 - i / 2]中有一个因数,那么另一个因数也在这个区间,所以抵消了。有奇数个因数出现的情况只能是这个数是某个数的平方数。所以问题变成1~n中有几个平方数,即对n开根号,可以采用O(logN)的二分查找法。但是我懒得写了,直接调用sqrt。

int bulbSwitch(int n) {
    return sqrt(n);
}


777题:Swap Adjacent in LR String    

一开始看错题目,以为X可以和左右的'L'或'R'互换,写完提交后才发现只有'RX'->'XR'和'XL'->'LX'两种换法,审题啊,审题,面Google的时候题目都没看完就开始做了,我也是服了我自己T_T。

我的解法比较蠢,用x_num记录end比start中多几个X,然后用一个指针指向当前比较的位置。写了一堆判断,主要是判断R和L不能交错,即R可以和X互换从而向右移,L可以和X互换从而向左移,但是R是不可能跑到L右边的(因为R和L不能互换)。

如果两者相等,下一位。

如果start中是R的话,那么end中该位置只能是'X',而且x_num要>=0,即之前没有过多余的L。

如果start中是L的话,那么end中该位置只能是'X',而且x_num要<0,即之前有多余的X。

如果start中是X的话,那么根据end中该位置是'L'还是'R'分别判断。

bool canTransform(string start, string end) {
    int len = start.size();
    int x_num = 0;
    for (int i = 0; i < len; i++) {
        if (start[i] == end[i])
            continue;
        if (start[i] == 'R' && end[i] == 'X' && x_num >= 0) {
            x_num++;
        }
        else if (start[i] == 'X') {
            if (x_num > 0 && end[i] == 'R') {
                x_num--;
            }
            else if (x_num <= 0 && end[i] == 'L') {
                x_num--;
            }
            else 
                return false;
        }
        else if (start[i] == 'L' && end[i] == 'X' && x_num < 0) {
            x_num++;
        }
        else
            return false;
    }
    if (x_num)
        return false;
    return true;
}
然后看了discussion,发现有解法用两个标记分别指向start和end中的位置,如果是X直接下一个,直到两者都不是'X'然后判断是否相等,以及此时的位置不是偏左(start[i]==R)或偏右(start[i]==L)。比我的解法简单粗暴,而且不容易写错Orz。


你可能感兴趣的:(Leetcode,Leetcode,Brainteaser,t)