数据结构的意义:
日常工作中遇到的问题可以用算法来有效解决,比如用热土豆问题,推销员问题等。而实现这些算法的有效手段,就是利用不同的数据结构了。比图,热土豆问题可以用队列或者链表,推销员问题用树。
简而言之就是,问题需要用算法来解决,实现这些算法就在于数据结构的掌握了。
1、Two sum
题目:给定一个整数组成的数组,给定一个特定的target,这个target是这个数组中的元素相加得到的。要求返回这两个元素在数组中的索引。
可以假设,在这个数组中只有唯一解,并且不能使用同一个元素。
例子:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]
作为刚刷的第一题,踩了几个坑:如果数组是[3,3],那么返回的索引list.index(3)是相同的。···· 如果用两个for循环,时间复杂度是O(n2)。超出时间限制。
解题技巧:不能用index,就用字典进行索引,不能用两个for循环,就用加数作为value,被加数作为key。
解:
dict_nums = {}
#字典以加数为key
for n in range(len(nums)):
m = target-nums[n]
#如果m已经在字典中了,说明列表中已经有符合条件的加数被存入了字典,这个加数的key就是索引值,得到解
if m in dict_nums:
return dict_nums[m],n
else:
#如果m不在字典中,以m为key,索引值n为value存入字典中,待用。
dict_nums[nums[n]]=n
2. Add Two Numbers
题目:给定两个非空链表,代表两个正数,数字以逆序存储在链表中,链表中每个节点存储一个单独的数字。要求将这两个数字相加,以同样的形式(逆序)返回链表。
可以假设,除了0本身,数字不以0开头。
例子:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
需要注意的坑:
- 1、两个数字长度不一样
- 2、有列表为空
- 3、两个数字都为0
用到的技巧: - 1、取余数:若n比10小,那么n%10=n
- 2、取整数:若n比10小,那么n//10=0
-------------------------------------------------------------------------------------------
可以利用上面两个方法,可以求得组成一个数字(807)的每个元素(8/0/7)。
余数 = x % 10
x = x//10
807//10=80,下次余数是0,在下次是8。
-------------------------------------------------------------------------------------------
我的做法: - 1、依次读取链表,利用while将个位数乘10,百位数再乘10,将链表中的数字表示出来。
- 2、将上面表示的两个链表相加,得到和以后,再按照上面技巧求得组成这个数字的每个元素,得到列表。
- 3、因为要求链表逆序存储,所以将上一步得到的列表反转以后,再按照链表添加节点的方法,依次添加个元素,得到链表。
我的缺点:
- 1、因为考虑到不能踩“两个数字不等”的坑,于是连续用了几个while。。。,其实用一个or就可以将两个数字联系起来了,一个为空时,另一个为真就可以让while继续循环下去。
- 2、因为考虑不能踩“单个数字相加可能有进位”的坑,于是把两个数字单独表示出来以后再相加再返回链表。。。其实可以再加一个变量carry表示进位符。这样,可以将单个的数字相加, 想办法计算下一个位的时候,加上carry就行了。
为了解题方便,可以多加变量
链表从head添加节点的步骤(已经有了head了)
1、构造一个新的节点
cur_new = ListNode(carry%10)
2、新来的节点的next指向原链表的head
cur_new.next = cur
3、head没了,就将新来的节点设置为head
cur_head = cur_new
比较好的改进:
def addTwoNumbers(self, l1, l2):
dummy = cur = ListNode(0)#定义一个头
carry = 0
while l1 or l2 or carry:#
if l1:
carry += l1.val
l1 = l1.next
if l2:
carry += l2.val
l2 = l2.next
cur.next = ListNode(carry%10)
cur = cur.next
carry //= 10
return dummy.next
但是这个链表,不是从头添加节点,是每次从链表末端添加节点,时间复杂度可能比较高。
0
0->7
0->7->0
0->7->0->8