"The Road to Algorithm Clearance" - some interesting topics in chapter 16

"The Road to Algorithm Clearance" study notes, record your own process of brushing the questions, please buy the author's book for detailed content.

Majority II

Retweet question 229
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

'''
方法一:摩尔投票法

时间复杂度:O(n)
空间复杂度:O(1)
'''

class Solution:
    def majorityElement(self, nums: list[int]) -> list[int]:
        n = len(nums)
        res = []
        cnt1 = 0
        cnt2 = 0
        n1 = None
        n2 = None

        # 筛选出出现次数最多的前两个元素
        for num in nums:
            if num == n1:
                cnt1 += 1
            elif num == n2:
                cnt2 += 1
            elif cnt1 == 0:
                n1 = num
                cnt1 += 1
            elif cnt2 == 0:
                n2 = num
                cnt2 += 1
            else:
                cnt1 -= 1
                cnt2 -= 1
        
        # 筛选出出现次数超过1/3的元素
        cnt1 = 0
        cnt2 = 0
        for num in nums:
            if num == n1:
                cnt1 += 1
            if num == n2:
                cnt2 += 1
        if cnt1 > n // 3:
            res += [n1]
        if cnt2 > n // 3:
            res += [n2]
        return res

nums = [3,2,3]
solu = Solution()
solu.majorityElement(nums)
[3]

The largest rectangle in the histogram

Lituo question 84
Given n non-negative integers, used to represent the height of each column in the histogram. Each column is adjacent to each other and has a width of 1.

Find the maximum area of ​​the rectangle that can be outlined in the histogram.

'''
方法一:双层循环(超时)

时间复杂度:O(n2)
空间复杂度:O(1)
'''

class Solution:
    def largestRectangleArea(self, heights: list[int]) -> int:
        n, ans = len(heights), 0
        if n != 0:
            ans = heights[0]
        for i in range(n):
            height = heights[i]
            for j in range(i, n):
                height = min(height, heights[j]) # 最小高度
                ans = max(ans, (j-i+1)*height) # 最大面积
        return ans

heights = [2,1,5,6,2,3]
solu = Solution()
solu.largestRectangleArea(heights)
10
'''
方法二:中心扩展法(超时)

时间复杂度:O(n2)
空间复杂度:O(1)
'''

class Solution:
    def largestRectangleArea(self, heights: list[int]) -> int:
        n = len(heights)
        ans = 0

        # 计算左边第一个高度小于heights[i]的索引和右边第一个小于heights[i]的索引
        for i in range(0, n):
            j = i - 1
            while j >= 0 and heights[j] >= heights[i]:
                j -= 1
            k = i + 1
            while k < n and heights[k] >= heights[i]:
                k += 1
            
            # 以i为最低点情况形成的最大矩阵面积
            ans = max(ans, heights[i] * (k - j - 1))
        return ans

heights = [2,1,5,6,2,3]
solu = Solution()
solu.largestRectangleArea(heights)
10
'''
方法三:中心扩展法(优化)

时间复杂度:O(n)
空间复杂度:O(n)
'''

class Solution:
    def largestRectangleArea(self, heights: list[int]) -> int:
        n = len(heights)
        l, r, ans = [-1]*n, [n]*n, 0

        for i in range(0, n):
            j = i - 1
            while j >= 0 and heights[j] >= heights[i]:
                j = l[j] # 优化
            l[i] = j

        for i in range(n-2, -1, -1):
            k = i + 1
            while k < n and heights[k] >= heights[i]:
                k = r[k] # 优化
            r[i] = k
        
        for i in range(n):
            ans = max(ans, heights[i] * (r[i] - l[i] - 1))
        return ans

heights = [2,1,5,6,2,3]
solu = Solution()
solu.largestRectangleArea(heights)
10
'''
方法四:单调栈

时间复杂度:O(n)
空间复杂度:O(n)
'''

class Solution:
    def largestRectangleArea(self, heights: list[int]) -> int:
        n, heights, st, ans = len(heights), [0]+heights+[0], [], 0
        for i in range(n+2):
            while st and heights[st[-1]] > heights[i]:
                ans = max(ans, heights[st.pop(-1)]*(i-st[-1]-1))
            st.append(i)
        return ans

heights = [2,1,5,6,2,3]
solu = Solution()
solu.largestRectangleArea(heights)
10

day of the week

Lituo question 1185.
Given a date, please design an algorithm to determine which day of the week it corresponds to.

'''
时间复杂度:O(n)
空间复杂度:O(1)
'''

class Solution:
    def dayOfTheWeek(self, day: int, month: int, year: int) -> str:
        months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        leap_months = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        
        # 1971-01-01为基准日期,是周五
        days = [
            'Friday',
            'Saturday',
            'Sunday',
            'Monday',
            'Tuesday',
            'Wednesday',
            'Thursday'
        ]

        diff = 0
        
        # 处理年
        for i in range(1971, year):
            if i % 400 == 0 or (i % 4 == 0 and i % 100 != 0):
                diff += 1
        diff += (year - 1971) * 365

        # 处理月
        for m in range(month - 1):
            if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):
                diff += leap_months[m]
            else:
                diff += months[m]
        
        # 处理日
        diff += day - 1
        return days[diff % 7]

day, month, year = 31, 8, 2019
solu = Solution()
solu.dayOfTheWeek(day, month, year)
'Saturday'

kettle problem

Leetok question 365
There are two water jugs with capacities of jug1Capacity and jug2Capacity liters respectively. The supply of water is unlimited. Determines whether it is possible to get targetCapacity liters exactly using both jugs.

If targetCapacity liters of water are available, use one or two of the above jugs at the end to hold the targetCapacity liters obtained.

you can:

Fill any jug
Empty any jug
Pour water from one jug to another until full or empty

'''
方法一:DFS(超时)
'''

class Solution:
    def canMeasureWater(self, x: int, y: int, z: int) -> bool:

        def dfs(x: int, y: int, z: int, state: set) -> bool:

            a, b = state
            if a == z or b == z or a + b == z:
                return True

            seen.add((a, b))
            states = set()
            states.add((x, b)) # 将x的水盛满
            states.add((a, y)) # 将y的水盛满
            states.add((0, b)) # 将x的水倒空
            states.add((a, 0)) # 将y的水倒空
            states.add((min(x, b + a), 0 if b < x - a else b - (x-a))) # 将x的水全部倒给y
            states.add((0 if a < y - b else a - (y - b), min(b + a, y))) # 将y的水全部倒给x

            res = False
            for state in states:
                if state in seen:
                    res |= False
                else:
                    res |= dfs(x, y, z, state)
            return res

        if x + y < z:
            return False
        state = (0, 0)
        seen = set(state)
        return dfs(x, y, z, state)

x, y, z = 3, 5, 4
solu = Solution()
solu.canMeasureWater(x, y, z)
True
'''
方法二:BFS

时间复杂度:O(xy)
空间复杂度:O(xy)
'''

class Solution:
    def canMeasureWater(self, x: int, y: int, z: int) -> bool:
        if x + y < z:
            return False
        
        queue = [(0, 0)]
        seen = set((0, 0))

        while len(queue) > 0:
            a, b = queue.pop(0)
            if a == z or b == z or a + b == z:
                return True

            states = set()

            states.add((x, b)) # 将x的水盛满
            states.add((a, y)) # 将y的水盛满
            states.add((0, b)) # 将x的水倒空
            states.add((a, 0)) # 将y的水倒空
            states.add((min(x, b + a), 0 if b < x - a else b - (x-a))) # 将x的水全部倒给y
            states.add((0 if a < y - b else a - (y - b), min(b + a, y))) # 将y的水全部倒给x

            for state in states:
                if state in seen:
                    continue
                queue.append(state)

                seen.add(state)
        
        return False

x, y, z = 3, 5, 4
solu = Solution()
solu.canMeasureWater(x, y, z)
True
'''
方法三:最大公约数

时间复杂度:O(log(max(a, b)))
空间复杂度:O(min(a, b))
'''

class Solution:
    def canMeasureWater(self, x: int, y: int, z: int) -> bool:

        if x + y < z:
            return False
        
        if z == 0:
            return True
        
        if x == 0:
            return y == z
        
        if y == 0:
            return x == z

        def GCD(a: int, b:int) -> int:
            return a if b == 0 else GCD(b, a % b)
        
        return z % GCD(x, y) == 0

x, y, z = 3, 5, 4
solu = Solution()
solu.canMeasureWater(x, y, z)
True

poor pig

Lituo No. 458
There are buckets of liquid, one of which contains poison, and the rest are filled with water. They all look the same from the outside. To figure out which bucket contains the poison, you can feed some pigs to drink and see if the pigs die. Unfortunately, you only have minutesToTest minutes to determine which bucket of liquid is poisonous.

The rules for feeding pigs are as follows:

Selecting several live pigs for feeding
allows piglets to drink from any number of buckets at the same time, and the process does not take time.
After the piglet drinks the water, there must be a cooling time of minutesToDie minutes. During this time, you can only observe and are not allowed to continue feeding the pigs.
After minutesToDie minutes have elapsed, all pigs that drink the poison will die, and all other pigs will survive.
Repeat this process until time runs out.
Given the number of buckets buckets, minutesToDie and minutesToTest, return the minimum number of pigs needed to determine which bucket is poisonous within the specified time.

'''
方法一:搜索法

时间复杂度:O(logn)
空间复杂度:O(1)
'''

class Solution:
    def poorPigs(self, buckets: int, minutesToDie: int, minutesToTest: int) -> int:
        cnt = 0
        while(minutesToTest // minutesToDie + 1) ** cnt < buckets:
            cnt += 1
        return cnt

buckets, minutesToDie, minutesToTest = 1000, 15, 60
solu = Solution()
solu.poorPigs(buckets, minutesToDie, minutesToTest)
5
import math
'''
方法二:n分法

时间复杂度:O(logn)
空间复杂度:O(1)
'''

class Solution:
    def poorPigs(self, buckets: int, minutesToDie: int, minutesToTest: int) -> int:
        states = minutesToTest // minutesToDie + 1
        return math.ceil(math.log(buckets) / math.log(states) - 1e-5)

buckets, minutesToDie, minutesToTest = 1000, 15, 60
solu = Solution()
solu.poorPigs(buckets, minutesToDie, minutesToTest)
5

Notebook - Github

Guess you like

Origin blog.csdn.net/cjw838982809/article/details/132527818