力扣刷题记录(一)
今天开始正式刷题,为找工作做准备,这篇博客用来记录一下;刷题顺序是先刷hot题目前100个
1.两数之和:
比较简单,一次就做出来。
思路:python的字典是哈希存储的,看了一下dict内置方法只有has_key,所以将值作为key,下标作为value,存储字典,然后遍历列表,以当前值为基准,用has_key判断(target-当前值)是否存在,存在则返回相应的下标即可。,代码如下:
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
info={}
# 将数据存入到字典当中
for i in range(len(nums)):
info[nums[i]] = i
for i in range(len(nums)):
temp = target-nums[i]
if info.has_key(temp):
return [info[temp],i]
2.两数相加
给了两个链表,代表两个数字,逆序存储。将两个数字相加,存储成相同的链表格式,返回。
第一次没做出来,看了答案才会的,第二次做有一些小bug,认真分析之后对一些细节地方理解更深刻了。
思路:不需要将两个数算出来然后相加,只需要将每一位相加,加的过程中判断是否有进位,如果有进位的话就多加一个1。另外注意这块没有新创建节点,而是直接使用a,b已经存在的节点,更改他们的值,注意这里是默认使用a节点,a为空了则使用b节点。另外注意循环最后一句是在拼接目标链表,而这一句
p = (a==null?b:a);是在更改目标链表的值为正确的值。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode p = null; ListNode a = l1; ListNode b = l2; int carry=0; //进位标志 int val; //每一位的和 while(a!=null || b!=null){ val = (a==null?0:a.val) + (b==null?0:b.val) + carry; //计算该位的值 carry = val>=10?1:0; val = val%10; //必须是小于10的 p = (a==null?b:a); //让p指向当前a,b里面不为空的,默认是a p.val = val; //更新节点的值 a = (a==null?null:a.next); //后移节点 b = (b==null?null:b.next); p.next=(a==null?b:a); //将p也后移一下,这一部无所谓,只是单纯的后移一下, } //最后的进位判断 if(carry>0){ p.next=new ListNode(1); } return l1; } }
好久不写了,一方面考试太多了,另一方面也是自己太懒了,买了一本《剑指offer》,配合这个好好刷一下题,另外准备按照题目难度刷
1.合并二叉树
题目描述:将两个二叉树进行合并, 如果两个树的当前节点都不为空,则将其值合并,否则取其中不为空的节点,最后返回一个新的树。
思路:虽然是一个比较简单的题,但是数据结构都忘了好多,开始还想了半天。总体上直接使用原来的内存空间就可以了, 这样就不需要再去申请内存创建新的节点了。采用先序遍历的方法遍历这棵树,当前节点如果有一个为空的,则返回另一个不空的,默认先判断t1,如果两个都不空的话就将值累加给t1的当前节点之后返回t1节点,都为空的情况已经包含在了第一种情况。
对一种情况的说明:因为我们是采用拼接的方法得到最终生成树的,所以并不是必须要遍历完两颗树的所有节点,比如如果当前t1.left为空,t2.left不为空,则将t2.left赋给t1.lft,并且t2.left的所有子节点也都跑到了t1.left之下,所以之后就就不需要再遍历t2.left的子节点了,因为t1.left没有子树,之后遍历的取值肯定都是t2的。
代码比较简单:
递归的方法:
class Solution { public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { //先序遍历两颗树,将和累加到A树当中,如果其中一个空的话,则直接返回另外一个不空的,并且可以把那个不为空的子节点直接扩展到其中去 if(t1 == null){ return t2; } if(t2 == null){ return t1; } t1.val += t2.val; //合并当前节点 t1.left = mergeTrees(t1.left, t2.left); //合并左子树,一个为空则不合并 t1.right = mergeTrees(t1.right, t2.right); //合并右子树 return t1; } }
面试时候如果你写递归的话,面试官会问你优化方法,所以还是老老实实的把非递归的也看一下:
非递归使用栈来完成,初始时候把两个根节点作为一项入栈,之后每一次从栈之中取出一个元素,判断该元素之中的两个节点为null的情况,
1.都为null的话,则无需再对这两个节点的子树进行讨论,跳过本次循环
2.如果有一个为空或者两个都不为空, 则将值累加到t1节点当中,并对t1.left和t1.right进行考察,如果为空的话,则直接将t2.left或者t2.right赋值给t1对应节点,如果不为空,则将t1.left和t2.left作为一项append到栈之中,之后进行考察。
代码: !!!!!!!这个非递归的代码是错误的,之前没有认真看,今天再次回顾时候才发现,错误代码就放在这里,以示警戒。
错误地方我不想,大家自己拿到leetcode上面运行一下,漏洞百出,之前太不仔细了,这个非递归代码就是cv的,当时也没注意是错的。
class Solution: def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode: if not t1: return t2 stack = [[t1,t2]] while stack: t = stack.pop() if (not t[0]) and (not t[1]): continue t[0].val += t[1].val if not t[0].left: t[0].left = t[1].left else: stack.append([t[0].left,t[1].left]) if not t[0].right: t[0].right = t[1].right else: stack.append([t[0].right, t[1].right]) return t1
附上自己想的正确的代码,用栈来转换递归的先序遍历,对于当前出栈元素有四种讨论,(都为空,(t[0非空,t[1]空)),(t[0]空,t[1]不空), (都不空),前两种情况做相同的处理,都是直接continue,第二种情况需要将t[1]嫁接到t[0]处,第三种情况相加节点,并添加新的元组到栈中。
代码如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
if not t1:
return t2
stack = [(t1,t2)]
while stack:
t = stack.pop()
if (not t[0] and not t[1]) or (t[0] and not t[1]):
continue
elif t[0] and t[1]:
t[0].val += t[1].val
if not t[0].left:
t[0].left = t[1].left
else:
stack.append((t[0].left,t[1].left))
if not t[0].right:
t[0].right = t[1].right
else:
stack.append((t[0].right, t[1].right))
elif not t[0] and t[1]:
t[0] = t[1]
return t1
当然这个if,else的排列可以深究一下,哈夫曼树,这里不说了。
2.两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x
和 y
,计算它们之间的汉明距离。
题目思路:这个题比较简单,就是比较二进制之中不相同的位的个数,要么直接异或运算,然后计算1的个数,要么先将他们转换为2进制之后计算不相同的位的个数,注意转换时候必须让他们总的位数相同,所以用or条件判断
class Solution:
def hammingDistance(self, x: int, y: int) -> int:
"""
首先将两个数字都转换为2进制数字存储为列表,之后找出来不一样的项的个数
或者直接进行异或运算,计算结果里面1的个数即可
"""
res = []
num = 0
while x!=0 or y!=0:
res.append((x%2, y%2))
x = x // 2
y = y // 2
for i in res:
if i[0] != i[1]:
num += 1
return num
但是这样比较慢,可以直接先异或,再统计1的个数
class Solution:
def hammingDistance(self, x: int, y: int) -> int:
"""
首先将两个数字都转换为2进制数字存储为列表,之后找出来不一样的项的个数
或者直接进行异或运算,计算结果里面1的个数即可
"""
return bin(x ^ y).count('1')
统计1的个数函数已经封装好了,但是也可以自己写,比较简单,判断该二进制最后一位是不是1,然后右移一位,再判断,再右移,直到二进制数为0。
class Solution:
def hammingDistance(self, x: int, y: int) -> int:
"""
首先将两个数字都转换为2进制数字存储为列表,之后找出来不一样的项的个数
或者直接进行异或运算,计算结果里面1的个数即可
"""
z = x ^ y
num = 0
while z!=0:
if z & 1 == 1:
num += 1
z = z >> 1
return num
后面两种方法一样快,第一种方法最慢,应该是运算次数比较多的缘故吧。