01.1~10题
# 01.求两数之和
- 题目
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]
1
2
3
4
5
6
2
3
4
5
6
- python答案
nums = [2,11,15,3,6,7]
target = 9
def towSum(nums, target):
dic = {}
for k, v in enumerate(nums):
if target - v in dic:
print(dic[target - v], k)
dic[v] = k
towSum(nums, target)
# 3 4
# 0 5
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- golang答案
package main
func towSum(nums []int, target int) {
dic := map[int]int{}
for k,v := range nums {
//fmt.Println(k,v)
//fmt.Println(dic)
_, ok := dic[target - v]
if ok{
println(dic[target-v], k)
}
dic[v] = k
}
}
func main() {
nums := []int{2,11,15,3,6,7}
towSum(nums, 9)
}
/*
3 4
0 5
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 02.链表反转
# 反转链表 (opens new window)
反转一个单链表。
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
1
2
2
# 2.1 python代码
#! /usr/bin/env python
# -*- coding: utf-8 -*-
class Node(object):
def __init__(self, val, next=None):
self.val = val
self.next = next
def list_reverse(head):
if head == None:
return None
L, R, cur = None, None, head # 左指针、有指针、游标
while cur.next != None:
L = R # 左侧指针指向以前右侧指针位置
R = cur # 右侧指针前进一位指向当前游标位置
cur = cur.next # 游标每次向前进一位
R.next = L # 右侧指针指向左侧实现反转
cur.next = R # 当跳出 while 循环时 cur(原链表最后一个元素) R(原链表倒数第二个元素)
return cur
if __name__ == '__main__':
'''
原始链表:1 -> 2 -> 3 -> 4
反转链表:4 -> 3 -> 2 -> 1
'''
lst = Node(1, Node(2, Node(3, Node(4)))) # 1-->2-->3-->4
l2 = list_reverse(lst) # 4-->3-->2-->1
print(l2.val) # 4
print(l2.next.val) # 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 2.2 golang
package main
import "fmt"
type ListNode struct {
val int
next *ListNode
}
func reverseList(head *ListNode) *ListNode {
var prev *ListNode
curr := head
for curr != nil {
next := curr.next
curr.next = prev
prev = curr
curr = next
}
return prev
}
func main() {
/*
原始链表:1 -> 2 -> 3 -> 4
反转链表:4 -> 3 -> 2 -> 1
*/
l1 := new(ListNode)
l2 := new(ListNode)
l3 := new(ListNode)
l4 := new(ListNode)
l1.val = 1
l1.next = l2
l2.val = 2
l2.next = l3
l3.val = 3
l3.next = l4
l4.val = 4
l := reverseList(l1)
for l != nil {
fmt.Println(l.val)
l = l.next
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 03.最大子序和
# 3.1 题目描述
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
1
2
3
2
3
# 3.2 python
- 基本思路就是遍历一遍,用两个变量,一个记录最大的和,一个记录当前的和。
如果当前和小于0,当前最长序列到此为止。以该元素为起点继续找最大子序列
- 时空复杂度貌似还不错......(时间复杂度 O(n),空间复杂度 O(l)
def maxSub(nums):
max_ = nums[0]
for i in range(1,len(nums)):
if nums[i] + nums[i-1] > nums[i]:
nums[i] += nums[i - 1]
if nums[i] > max_:
max_ = nums[i]
return max_
nums = [-2,1,-3,4,-1,2,1,-5,4]
print(maxSub(nums)) # 6 ==》[4,-1,2,1]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 3.3 golang
- 基本思路就是遍历一遍,一个记录最大的和,一个记录当前的和。
- 如果当前的和大于0,就继续加下一个元素,然后比较max,如果更大就更新max
- 时空复杂度貌似还不错......(时间复杂度 O(n),空间复杂度 O(l)
package main
import "fmt"
func maxSub(nums []int) int {
max := nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] + nums[i-1] > nums[i] { // 如果nums[i-1]当前和大于0,记录当前的和
nums[i] += nums[i-1]
}
if nums[i] > max { // 当前和与记录最大的和比较,如果当前和更大就更新
max = nums[i]
}
}
return max
}
func main() {
nums := []int{-2,1,-3,4,-1,2,1,-5,4}
fmt.Println( maxSub(nums) ) // 6
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 04.合并两个有序链表
# 4.1 题目描述
- 将两个升序链表合并为一个新的 升序 链表并返回。
- 新链表是通过拼接给定的两个链表的所有节点组成的。
输入:l1 = 1->2->4, l2 = 1->3->4
输出:1->1->2->3->4->4
1
2
2
# 4.2 解题思路
- 我们可以用迭代的方法来实现上述算法。
- 当 l1 和 l2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里
- 当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。
class ListNode:
def __init__(self,val=None, next=None):
self.val = val
self.next = next
def mergeTwoLists(l1, l2):
head = ListNode(-1) # head是新链表的头部
cur = head # 我们维护一个cur 指针,我们需要做的是调整它的 next 指针
while l1 and l2: # 我们重复以下过程,直到 l1 或者 l2 指向了 null
# 如果l1值小就将l1节点加到新链表后面
if l1.val <= l2.val:
cur.next = l1
l1 = l1.next
# 否则,我们对 l2 做同样的操作
else:
cur.next = l2
l2 = l2.next
cur = cur.next # 不管我们将哪一个元素接在了后面,我们都需要把 prev 向后移一位
# 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
cur.next = l1 if l1 is not None else l2
return head.next
l1 = ListNode(1,ListNode(2,ListNode(4))) # 1->2->4
l2 = ListNode(1,ListNode(3,ListNode(4))) # 1->3->4
l = mergeTwoLists(l1, l2)
while l:
print(l.val) # 1 1 2 3 4 4
l = l.next
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 05.整数反转
# 5.1 题目描述
# 例1
输入:x = 123
输出:321
# 例2
输入:x = -123
输出:-321
1
2
3
4
5
6
7
2
3
4
5
6
7
# 5.2 解题思路
以12345为例,先拿到5,再拿到4,之后是3,2,1
我们按这样的顺序就可以反向拼接处一个数字了,也就能达到 反转 的效果。
怎么拿末尾数字呢?好办,用取模运算就可以了
- 1、将12345 % 10 得到5,之后将12345 / 10
- 2、将1234 % 10 得到4,再将1234 / 10
- 3、将123 % 10 得到3,再将123 / 10
- 4、将12 % 10 得到2,再将12 / 10
- 5、将1 % 10 得到1,再将1 / 10
但是要注意32 位的有符号整数,则其数值范围为
[−2^31, 2^31 − 1]
- 假设有1147483649这个数字,它是小于最大的32位整数2147483647的
- 但是将这个数字反转过来后就变成了9463847411,这就比最大的32位整数还要大了
- 这样的数字是没法存到int里面的,所以肯定要返回0(溢出了)。
def reverse(x):
res = 0
x1 = abs(x)
while(x1!=0): # 3//10 = 0 {如果等于0,代表数字所有数全部遍历完成}
temp = x1%10 # 321 % 10 = 1 (取出数字个位数)
if res > 214748364 or (res==214748364 and temp>7):
return 0
if res<-214748364 or (res==-214748364 and temp<-8):
return 0
res = res*10 + temp
x1 = x1 // 10 # 321 // 10 = 32 (去除数字个位数)
return res if x >0 else - res
print( reverse(-321) ) # -123
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 不考虑32位系统边界问题的解法
def reverse(x):
res = 0
x1 = abs(x)
while(x1!=0): # 3 // 10 = 0 {如果等于0,代表数字所有数全部遍历完成}
temp = x1%10 # 321 % 10 = 1 (取出数字个位数)
res = res*10 + temp # 从右向左依次拼接
x1 = x1 // 10 # 321 // 10 = 32 (去除数字个位数)
return res if x >0 else - res
print( reverse(-321) ) # -123
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 06.青蛙跳&爬楼梯
# 6.1 题目描述
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级。
- 求该青蛙跳上一个n级的台阶总共有多少种跳法
# 6.2 实现思路
- 思路
# 1、n=1 时只有一种方法
f(1) = 1
# 2、n=2 时当第一次跳一个台阶时,有一种方法,当第一次跳两个台阶时有一种方法
f(2) = 1+1 = 2
# 3、n=3 倒推最后一跳跳一步有f(n-1)种方法 最后一跳跳两步f(n-2)
f(3) = f(2) + f(1) = 3
# 4、n>2 以此类推
f(n) = f(n-1)+f(n-2)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 二级台阶
- 当为1级台阶: 剩n−1 个台阶,此情况共有 f(n-1)种跳法
- 当为2级台阶: 剩 n-2个台阶,此情况共有 f(n-2)种跳法。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(1000000000) #设置系统最大递归深度
def fib(n):
if n <= 2:
return n
else:
return fib(n-1) + fib(n-2)
print(fib(4)) # 5
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 6.3 n级台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
求该青蛙跳上一个n级的台阶总共有多少种跳法
思路
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(1000000000) #设置系统最大递归深度
def fib(n):
if n <= 2:
return n
else:
return 2 * fib(n - 1)
print(fib(4)) # 8
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- n级台阶推演
# 1、n=1 时只有一种方法
f(1) = 1
# 2、n=2 时当第一次跳一个台阶时,有一种方法,当第一次跳两个台阶时有一种方法
f(n) = 1+1 = 2
# 3、n=3 时当第一次跳一个台阶时有f(3-1)中方法,当第一次跳两个台阶时有f(3-2)中方法,当第一次跳3个台阶时有f(3-3)种跳法
f(n) = 2+1 = 3
# 4、n>2 以此类推
f(n) = f(n-1)+f(n-2)+......f(0)
'''
f(n) = f(n-1)+f(n-2)+......f(0)种跳法
f(n-1) = f(n-2)+f(n-3)+.....f(0)
f(n)-f(n-1)=f(n-1)
所以f(n) = 2*f(n-1)
'''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 6.4 三级台阶问题
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(1000000000) #设置系统最大递归深度
def fib(n):
if n <= 2:
return n
elif n == 3:
return 4
else:
return fib(n-1) + fib(n-2) + fib(n-3)
print(fib(4)) # 7
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 07.有效的括号
# 事例1
输入:s = "()[]{}"
输出:true
# 事例2
输入:s = "(]"
输出:false
1
2
3
4
5
6
2
3
4
5
6
- 解题思路
def isValid(s):
d = {
")": "(",
"]": "[",
"}": "{",
}
stack = []
for ch in s:
if ch in d: # 如果字符串是 右边括号
# 如果右括号和栈顶元素不能成对匹配,那么证明匹配失败,返回False
if not stack or stack[-1] != d[ch]:
return False
stack.pop() # 如果 栈顶元素 和 当前元素能够成对匹配,弹出栈顶元素
else:
stack.append(ch) # 如果是左侧括号,直接入栈
return not stack
s1 = "([]{})"
s2 = "([(])"
print(isValid(s1)) # True
print(isValid(s2)) # False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 08.买卖股票的最佳时机
# 8.1 题目要求
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
输入: [7,4,6,3,1]
输出: 2
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
1
2
3
2
3
# 8.2 答案
有 买入(buy) 和 卖出(sell) 这两种状态
当天买的话意味着损失
-prices[i]
,当天卖的话意味着增加prices[i]
,当天卖出总的收益就是buy+prices[i]
所以我们只要考虑当天买和之前买哪个收益更高,当天卖和之前卖哪个收益更高。
- buy = max(buy, -price[i]) (注意:根据定义 buy 是负数)
- sell = max(sell, prices[i] + buy)
s = [7,4,6,3,1]
def maxProfit(prices):
if len(prices) <= 1:
return 0
buy = prices[0] # 当天买的话意味着损失 -prices[i]
sell = 0
for i in prices:
buy = min(buy, i) # 当前买的价格 比 以前买入的大,就在当前节点买入
sell = max(sell, i-buy) # 卖的价钱 = 现在成交价格i - 购买价格buy
return sell
print(maxProfit(s)) # 2
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 09.买卖股票最大亏损
# 9.1 题目要求
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大亏损。
注意你不能在买入股票前卖出股票。
输入: [7,6,4,3,1]
输出: -6
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
1
2
3
2
3
# 9.2 答案
s = [7,6,4,3,1]
class Solution:
def maxProfit(self, prices):
if len(prices)<=1:
return 0
buy = -prices[0]
sell=0
for i in prices:
buy = min(buy, -i)
sell= min(sell, i + buy)
return sell
print( Solution().maxProfit(s) )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 10.回文数
# 10.1 题目描述
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
输入:x = 121
输出:true
输入:x = -121
输出:false
1
2
3
4
2
3
4
# 10.2 解题思路
- 方法1
def huiwen(x):
x = str(x)
left, right = 0, len(x) - 1
while left < right and x[left] == x[right]:
left = left + 1
right = right - 1
return left == right or x[left] == x[right]
print( huiwen(121) ) # True
print( huiwen(-121) ) # False
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
编辑 (opens new window)
上次更新: 2022/09/21, 11:19:29