题237. 删除链表中的节点
题意
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。
现有一个链表 – head = [4,5,1,9],它可以表示为:
eg
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
解题
本题需要注意的点就是给定的参数只有要删除的节点,而我们一般对链表的删除操作最常用的做法是对删除节点的前一个节点进行操作。
比如前一个节点为prev,那么只需要令prev.next = node.next,就能把node给删除了。
而本题中无法获取node的前一个链表,只能转换做法,把node的下一个节点复制到node,而后删除这个节点,这样也相当于删除了node。
node.val=node.next.val
node.next=node.next.next
题238. 除自身以外数组的乘积
题意
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
eg
输入: [1,2,3,4]
输出: [24,12,8,6]
提示: 题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
解题
看到题目我们马上能想到的方法就是先计算一个总乘积,然后对数组进行遍历,每次在输出数组上添加总乘积处理当前数。 但由于说明中要求不能使用出发,所以排除了。
如果选择遍历时将除当前数之外的所有数乘起来,则时间复杂度会达到O( n 2 n^2 n2),也不满足要求,排除。
存储左右乘积
上面这个做法之所以会达到 O( n 2 n^2 n2) 的时间复杂度,是因为在遍历时,对于每个数都要重新计算左右的乘积,其实多了很多不必要操作,我们可以先用两个数组把从左往右和从右往左的乘积存储起来,然后在计算输出数组的时候就可以直接使用了。
- 前后分别遍历,得到左右乘积
- 一次循环,每次将左右乘积相乘,加到输出数组
n=len(nums)
left,right=[1]*n,[1]*n
res=[]
for i in range(1,n):
left[i]=left[i-1]*nums[i-1]
for i in range(n-2,-1,-1):
right[i]=right[i+1]*nums[i+1]
for i in range(n):
res.append(left[i]*right[i])
return res
时间复杂度为O(n)
改进
上面这个方法进行了三次遍历,那么实际上,可以把第二次和第三次合起来。
即先存左边的乘积,然后从右边开始遍历,一边计算右边乘积后再乘左边乘积,一边添加到输出数组。 当然左右顺序反过来也可以。
而且,我们再进行简化,把左乘积数组和输出数组进行合并,这样就满足了进阶的要求。
n=len(nums)
res=[1]*n
for i in range(1,n):
res[i]=res[i-1]*nums[i-1]
tmp=1
for i in range(n-1,-1,-1):
res[i]=tmp*res[i]
tmp*=nums[i]
return res
时间复杂度为 O(n),空间复杂度为O(1)
题292. Nim 游戏
题意
你和你的朋友,两个人一起玩 Nim 游戏:
桌子上有一堆石头。
你们轮流进行自己的回合,你作为先手。
每一回合,轮到的人拿掉 1 - 3 块石头。
拿掉最后一块石头的人就是获胜者。
假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true;否则,返回 false 。
eg
输入: n = 4
输出: false
解释: 如果堆中有 4 块石头,那么你永远不会赢得比赛;
因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。
解题
本题是一道博弈论题目,最好的解法就是题意分析,因为取 1,2,3皆可,那么当你面临的数字是4时,必然会输。
由此推导,剩余4颗石头的时候是输,那么就要避免剩余四颗
而当剩下的是八颗的时候,你又无法避免会碰到下一轮是四颗石头的窘境,以此类推就可以发现,只要自己面临的是四的倍数颗石头,就必输无疑。
so,只需要判断是否剩余4的倍数颗石头就行了。
return n%4!=0