挑战60天(第2天/ 7月-23日),每天Leetcode刷题,数据结构与算法
数组模块
leetcode189题:轮转数组
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
不要返回任何东西,在原数组上修改
自己写的错误案例,都不用反转,列表存一下加一起就行。不得行,如果K的值比列表长度还大,需要先取余,因为要在原来的nums上修改
思路二:又想了一个方法,但是时间超时了。
暴力的方法,进行K次循环,每次把最后的一个数用temp记录,然后把前面的所有数往后移动一位(n-1)次,最后把temp给数组第一个位置。进行K次就行了。
方法应该是对的。通过了34/38
回顾一下python的reverse()反转函数,会改变原来的列表,
试了一下,列表切片调用reverse()不会有结果,只有传入整个列表才行
解题思路:
需要写一个revers()方法,可以在指定的片段上进行反转。
1、将所有的列表反转一下
2、前面k个反转一下,后面k到n-1反转一下
需要考虑一下,K的长度,K=len(nums)的时候,第三次调用self.revsere的时候,K就越界了。
K=0的时候,中间那次reverse没有改变。
看能不能把它分开来写。
class Solution(object):
def rotate(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: None Do not return anything, modify nums in-place instead.
"""
# for i in range(k):
# i = 1
# temp = nums[-1]
# for j in range(len(nums)-1):
# nums[-i] = nums[-(i+1)]
# i += 1
# nums[0] = temp
# 需要考虑k=1和k=列表长度的情况
k = k % len(nums)
self.reverse(nums, 0, len(nums)-1)
self.reverse(nums, 0, k-1)
self.reverse(nums, k, len(nums)-1)
def reverse(self, nums, left, right):
while left < right:
temp = nums[left]
nums[left] = nums[right]
nums[right] = temp
left += 1
right -= 1
会出现这种情况,K的值是大于len(nums)的:当k的值等于len(nums)的时候是没有变化的,所有最好用
k = k % len(nums) 取余数,得到最后的改变
0238. 除自身以外数组的乘积
题目:
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请不要使用除法,且在 O(n) 时间复杂度内完成此题。
解题思路:最简单的就是全部乘起来,遍历列表,每个位置返回乘起来的值除以当前值。
构造一个答案数组 res,长度和数组 nums 长度一致。先从左到右遍历一遍 nums 数组,将 nums[i] 左侧的元素乘积累积起来,存储到 res 数组中。再从右到左遍历一遍,将 nums[i] 右侧的元素乘积累积起来,再乘以原本 res[i] 的值,即为 nums 中除了 nums[i] 之外的其他所有元素乘积。
中等难度的题,不会啊。看别人写的。
class Solution(object):
def productExceptSelf(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
res =[1 for i in range(len(nums))]
left = 1
for i in range(len(nums)):
res[i] *= left
left *= nums[i]
right = 1
for i in range(len(nums)-1, -1, -1):
res[i] *= right
right *= nums[i]
return res
左到右的时候计算乘积,右到左的时候就更新出结果。
冒泡排序
import random
def bubble_sort(li):
# 只需要冒泡n-1次, 因为最后只有一个数的时候不用排。
for i in range(len(li)-1):
# 为什么要加exchange ,当列表执行一次后没有发生顺序改变,就可以返回了
exchange = False
# 最开始只需要,比较列表减一个数,往后每一次循环只比较无序区的数,所以要减i
for j in range(len(li) - i - 1):
if li[j] > li[j+1]:
# 同时交换两个数
li[j], li[j+1] = li[j+1], li[j]
exchange = True
# 打印每一趟的值
print(li)
if not exchange:
return
# 这样会增加复杂度
# if li == li:
# return li
li = [random.randint(0,10) for i in range(10)]
# li1 = [1,2,3,4,5,6,7]
print(li)
bubble_sort(li)
冒泡排序方法比较适合于参加排序序列的数据量较小的情况,尤其是当序列的初始状态为基本有序的情况。
排序稳定性:由于元素交换是在相邻元素之间进行的,不会改变值相同元素的相对位置,因此,冒泡排序法是一种 稳定排序算法。
选择排序
每次选一个最小的出来,下一次从剩下的选一个最小的出来,执行n-1次。
def select_sort(li):
for i in range(len(li)-1): # i是第几趟
min_loc = i
for j in range(i+1, len(li)):
if li[j] < li[min_loc]:
min_loc = j
li[i], li[min_loc] = li[min_loc], li[i]
print(li)
li1 = [3,4,2,1,5,6,8,7,9]
li = [1,4,2,4,5,6,7,8,9]
print(li1)
select_sort(li1)
插入排序
选牌插入合适为止
1、从列表第二个数开始取, 取出来的数和列表前的数比较。比较的时候是从右往左,如果取出的数比当前遍历数小则,当前数往右移一个,继续比较,停止条件为列表前的数比完了,或者取出的数比当前数大。
def insert_sort(li):
for i in range(1, len(li)): # 表示摸到的牌的下标
j = i - 1 # 手里的牌的下标。
# 不知道要循环多少次用 while
temp = li[i]
while j >= 0 and li[j] > temp:
li[j+1] = li[j]
j -= 1
li[j+1] = temp
# print(li)
li = [5,7,4,6,3,1,2,9,8]
print(li)
insert_sort(li)
print(li)
快速排序(NB三人组)
def quick_sort(li, left, right):
if left < right:
mid = partition(li, left, right)
quick_sort(li, left, mid-1)
quick_sort(li, mid+1, right)
def partition(li, left, right):
tmp = li[left]
while left < right:
while li[right] >= tmp and left < right: # 从右边找比tmp小的数,如果比tmp大往左移一位
right -= 1
li[left] = li[right] # 把右边值写到左边空位
while li[left] < tmp and left < right:
left += 1
li[right] = li[left]
li[left] = tmp
return left
li = [5,7,4,6,3,1,2,9,8]
quick_sort(li, 0, len(li)-1)
print(li)
快速排序的另一种写法,空间复杂度高一点。
def quick_sort(li):
if len(li) <= 1:
return li
else:
mid = li[0]
smaller = [x for x in li[1:] if x <= mid]
greater = [x for x in li[1:] if x > mid]
return quick_sort(smaller) + [mid] + quick_sort(greater)
li = [5,7,4,6,3,1,2,9,8]
print(quick_sort(li))
堆排序(NB三人组)
完全二叉树,可以不满,但是要从左到右过来。
父节点和左孩子节点编号:i—> 2i + 1
父节点和右孩子节点编号:i—> 2i + 2
堆:特殊完全二叉树,大根堆,父节点都比子节点大。
堆的向下调整:节点左右都是堆,整个不是堆。通过向下调整编程一个堆。
堆排序:从顶出数,把尾数放顶上,进行一次向下调整。
构造堆
从下往上构造。
首先写向下调整
# 向下调整
def sift(li, low, high):
i = low
j = 2 * i + 1
tmp = li[low]
while j <= high:
if j + 1 <= high and li[j+1] > li[j]:
j = j + 1
if li[j] > tmp:
li[i] = li[j]
i = j
j = 2 * i + 1
else:
li[i] = tmp
break
li[i] = tmp
# 建堆,从下到上,并且取数
def head_sort(li):
# 建堆
n = len(li)
# 找i的位置,第一个小堆的堆顶,往上循环。把n-1当做所有的high都够了
for i in range((n-2)//2, -1, -1):
sift(li, i, n-1) # 循环完了,堆就建好了
# 取数出来,取n个数
for i in range(n-1, -1, -1):
# i指向的是堆的最后一个元素
li[0],li[i] =li[i], li[0] # 把堆顶的元素和,最后一个元素互换。
sift(li, 0, i-1) # 每次向下high的位置要减一
li = [i for i in range(100)]
import random
random.shuffle(li)
print(li)
head_sort(li)
print(li)