挑战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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值