LeetCode:Brainteaser Problems

189 篇文章 3 订阅
151 篇文章 2 订阅
LeetCode:292. Nim Game

问题描述:

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

示例:

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

问题分析:

(1)首先,你第一个开始拿石头,这个很重要的。
(2)看例子,(你)(他,你)、(他,你)... ...(他,你)第一个括号是你第一次拿石头,后面的括号是你们两个轮流拿石头。因为每次最多可以拿 1-3 块石头,现在先看后面的括号,后面的括号无论对手拿几个,你拿的个数只要他拿的个数和= 4 ,那么你就可以拿到最后,前提是,第一次你拿完之后剩余的石头个数是 4 的倍数。是不是很简单?

Python3实现:

# @Time   :2018/6/27
# @Author :LiuYinxing



class Solution:
    def canWinNim(self, n):
        return n % 4 != 0


if __name__ == '__main__':
    n = 5
    solu = Solution()
    print(solu.canWinNim(n))
LeetCode:319. Bulb Switcher

问题描述:

319. 灯泡开关

初始时有 个灯泡关闭。 第 1 轮,你打开所有的灯泡。 第 2 轮,每两个灯泡你关闭一次。 第 3 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第 i 轮,每 个灯泡切换一次开关。 对于第 轮,你只切换最后一个灯泡的开关。 找出 轮后有多少个亮着的灯泡。

示例:

输入: 3
输出: 1 
解释: 
初始时, 灯泡状态 [关闭, 关闭, 关闭].
第一轮后, 灯泡状态 [开启, 开启, 开启].
第二轮后, 灯泡状态 [开启, 关闭, 开启].
第三轮后, 灯泡状态 [开启, 关闭, 关闭]. 
你应该返回 1,因为只有一个灯泡还亮着。

问题分析:

先看下表:


n = 9 时,对第 i 个灯泡,进行求它们各自的因子,很显然,它们的因子的个数为奇数个时,它们最后一定是亮着。

(1)那么问题来了,那些数的因子是奇数个那?

从上面表格可以看出来?如果这个数能被完全开方(例如1, 4, 9),那么这个数一定是有奇数个因子。

(2)为什么平方数的因子个数一定是奇数个?

因为,假设 m = a * a, 很显然 m的因子有一个a, 如果存在其他因子,那么这个因子一定小于 a 或者大于 a, 此时一定有一个大于a的数或者小于a的数,与其的乘积为 m,所以如果存在其他因子一定成对出现,再加上 a 本身1个,所有因子的个数一定是奇数个

(3)现在问题就是变成了求n一共有多个平方数了?

很显然 n 的平方数个数为 sqrt(n) 下取整。

Python3实现:

# @Time   :2018/6/27
# @Author :LiuYinxing
import math


class Solution:
    def bulbSwitch(self, n):
        return int(math.sqrt(n))


if __name__ == '__main__':
    n = 6
    solu = Solution()
    print(solu.bulbSwitch(n))
LeetCode:777. Swap Adjacent in LR String

问题描述:

777. 在LR字符串中交换相邻字符

在一个由 'L' , 'R' 和 'X' 三个字符组成的字符串(例如"RXXLRXRXL")中进行移动操作。一次移动操作指用一个"LX"替换一个"XL",或者用一个"XR"替换一个"RX"。现给定起始字符串start和结束字符串end,请编写代码,当且仅当存在一系列移动操作使得start可以转换成end时, 返回True

示例 :

输入: start = "RXXLRXRXL", end = "XRLXXRRLX"
输出: True
解释:
我们可以通过以下几步将start转换成end:
RXXLRXRXL ->
XRXLRXRXL ->
XRLXRXRXL ->
XRLXXRRXL ->
XRLXXRRLX

注意:

  1. 1 <= len(start) = len(end) <= 10000
  2. startend中的字符串仅限于'L''R''X'

问题分析:

(1)无论怎么替换,R、L之间的相对位置不会改变的。
(2)XL-->LX,说明,start串中的字符 L 只能向左移动。进一步说明,字符串 start、end 相同位置的左边,start串中的L个数不应该大于 end 串中的 L 个数字。
(3)RX-->XR,说明,start串中的字符 R 只能向右移动。进一步说明,字符串 start、end 相同位置的左边,start串中的R个数不应该小于 end 串中的 R 个数字。
(4)那么剩余的情况,就可以从字符串 start 替换到 end 了。

Python3实现:

class Solution(object):
    def canTransform(self, start, end):
        if start.replace('X', '') != end.replace('X', ''): return False  # 判断相对位置是否一样

        cntL1 = cntL2 = cntR1 = cntR2 = 0
        for v1, v2 in zip(start, end):  # 进行统计计算
            if v1 == 'L': cntL1 += 1
            elif v1 == 'R': cntR1 += 1
            if v2 == 'L': cntL2 += 1
            elif v2 == 'R': cntR2 += 1
            if cntL1 > cntL2 or cntR1 < cntR2: return False
        return True


if __name__ == '__main__':
    start, end = 'RXXLRXRXL', 'XRLXXRRLX'
    solu = Solution()
    print(solu.canTransform(start, end))

欢迎指正哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值