LeetCode Hot100 -- string topic

Posted by EPCtech on Mon, 24 Jan 2022 00:06:51 +0100

128. Longest continuous sequence

Given an unordered integer array nums, find out the length of the longest sequence of consecutive numbers (not ascending but continuous) (sequence elements are not required to be continuous in the original array).

Idea:

class Solution:
    def longestConsecutive(self, nums):
        if not nums:
            return 0

        nums.sort()
        res=1
        max_len=1

        for i in range(1,len(nums)):
            if nums[i]==nums[i-1]:
                continue
            elif (nums[i]-nums[i-1])==1:
                res+=1
                max_len=max(max_len,res)
            else:
                res=1

        return max_len

Dynamic programming, first sort in ascending order, and then traverse. Save the maximum length with a hash table. When traversing num, find num-1 from the hash table. If so, the current maximum length is Map[num-1]+1

 class Solution(object):
     def longestConsecutive(self, nums):
         nums.sort()
         num2len = {}
         maxv = 0
         for num in nums:
             if num not in num2len: 
                 left_len = num2len.get(num-1,0)
                 cur_len = left_len + 1
                 num2len[num] = cur_len
                 if maxv < cur_len:
                     maxv = cur_len
         return maxv

312. Poke the balloon

There are n balloons, numbered from 0 to n - 1. Each balloon is marked with a number, which is stored in the array num.

Now I ask you to pierce all the balloons. Pierce the ith balloon and you can get nums[i - 1] * nums[i] * nums[i + 1] coins. Here i - 1 and I + 1 represent the sequence numbers of the two balloons adjacent to I. If i - 1 or I + 1 exceeds the bounds of the array, it is considered a balloon with a number of 1.

Find the maximum number of coins you can get.

Idea:

  1. dp[i][j] represents the maximum number of coins that can be obtained by the ball between I and j, K represents the last punctured balloon, and dp[i][k] + nums[i]*nums[k]*nums[j] + dp[k][j]. Then dp[i][j] is equal to traversing K between I and j to find the largest one.
  2. When traversing, it is traversed according to the interval length between i and j, because the longer interval comes from the shorter interval. In this way, all interval lengths can be obtained through dynamic programming.

Suppose this interval is an open interval, the leftmost index i and the rightmost index j
What i mean by "open range" here is that we can only poke the balloon between i and j, i and j don't poke

The DP idea is like this. Don't worry about how the front is poked. You just care about which balloon is the last one punctured in this interval
The last balloon to burst is k

k is the last balloon in this range!!!!!

Suppose the last balloon is pink, and k is the index of the pink balloon

Then, since k is the last one to be poked, what is the scene before it is poked?

Because it was the last one to be punctured, there was no ball around it! There's no ball! Only the beginning and end of this open interval i and j It's over!
That's why DP The state transition equation is only and i and j The position is related to the number
 hypothesis dp[i][j] Indicates the open interval (i,j) The most gold coins you can get in
 So what are you doing in this case (i,j) The gold coins obtained by opening the interval can be dp[i][k] and dp[k][j] Transfer
 If you choose to poke the balloon now k,Then the number of gold coins you get is:

 

Then you may want to ask again. I can get val[i]*val[k]*val[j] so many gold coins by poking and exploding pink balloons. I understand (because there are only three balloons left when poking and exploding K), but why do you just add dp[i][k] and dp[k][j] before and after? Because K is the last one to be punctured, the things on both sides of K in the (i,j) interval must be punctured first. The left and right sides do not interfere with each other. You can taste it carefully. This is why we need to look at the "last punctured" balloon in DP, so that the left and right sides do not interfere with each other. This is probably an idea of divide and conquer

Then, you start to calculate when there are only three numbers in the (i,j) open interval, and store the maximum value of gold coins that can be obtained between each cell
Then slowly expand to a larger interval, and calculate a larger interval by using the calculated numbers in the cells

class Solution:
    def maxCoins(self, nums):

        # nums adds 1 from beginning to end to facilitate boundary processing
        nums.insert(0, 1)
        nums.insert(len(nums), 1)

        dp = [[0] * (len(nums)) for _ in range(len(nums))]

        def range_best(i, j):
            m = 0
            # k is the last punctured balloon in the interval (i,j)
            for k in range(i + 1, j):  # The value of k is in the open interval of (i,j)
                # The following are open intervals (i,k), (k,j)
                left = dp[i][k]
                right = dp[k][j]
                tmp = left + nums[i] * nums[k] * nums[j] + right
                if tmp > m:
                    m = tmp
            dp[i][j] = m

        # Cycle the length of each interval
        for delta in range(2, len(nums)):  # Interval length #The length starts from 3 and n starts from 2
            # The length of the open interval will be from 3 to len(nums)
            # Because range is taken here, the last number is len(nums)-1
            # For each interval length, i at the beginning of the cyclic interval
            for start in range(0, len(nums) - delta):  # i+n = len(nums)-1
                # Calculate the maximum number of gold coins in this interval
                range_best(start, start + delta)

        return dp[0][len(nums) - 1]

121. The best time to buy and sell stocks

Given an array, its i-th element is the price of a given stock on day I.

If you are allowed to complete only one transaction at most (i.e. buy and sell a stock once), design an algorithm to calculate the maximum profit you can make.

Idea:

Considering only traversing once, to find the maximum profit is equivalent to finding two indexes a and B, where b > A, and the profit = prices[b] - prices[a] is the maximum

Let's suppose we buy stocks ourselves. Over time, we can choose whether to sell our shares or not every day. So, suppose on day i, if we want to sell stocks today, how much money can we make?

Obviously, if we were really buying and selling stocks, we would think: if only I had bought stocks at the lowest point in history! Great. In the title, we just use a variable to record a historical lowest price minprice, and we can assume that our stock was bought that day. Then the profit we can get from selling stocks on day I is price [i] - minprice.

Therefore, we only need to traverse the price array once, record the historical lowest point, and then consider such a question every day: if I bought at the historical lowest point, how much money can I make from selling today? When we consider all the days, we get the best answer

The above traversal includes all cases, then the maximum profit is the maximum value

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        inf = int(1e9)
        minprice = inf
        maxprofit = 0
        for price in prices:
            maxprofit = max(price - minprice, maxprofit)
            minprice = min(price, minprice)
        return maxprofit

238. Product of arrays other than itself

An integer array num of length N, where n > 1, returns the output array output, where output[i] is equal to the product of all elements in num except num [i]. Division is not required.

Example:

 input: [1,2,3,4] output: [24,12,8,6]

Idea:

Traverse one round from left to right to get the product of all elements on the left of each index position. Then multiply from right to left by the product to the right of each index position.

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        length = len(nums)
        
        # L and R represent the product list on the left and right sides respectively
        L, R, answer = [0]*length, [0]*length, [0]*length
        
        # L[i] is the product of all elements to the left of index I
        # For the element with index '0', L[0] = 1 because there is no element on the left
        L[0] = 1
        for i in range(1, length):
            L[i] = nums[i - 1] * L[i - 1]
        
        # R[i] is the product of all elements to the right of index I
        # For the element with index 'length-1', because there is no element on the right, R[length-1] = 1
        R[length - 1] = 1
        for i in reversed(range(length - 1)):
            R[i] = nums[i + 1] * R[i + 1]

        # For index I, the product of all elements except num [i] is the product of all elements on the left multiplied by all elements on the right
        for i in range(length):
            answer[i] = L[i] * R[i]
        
        return answer

 72. Edit distance

Here are two words word1 and word2. Please calculate the minimum operands used to convert word1 to word2.

Idea:

  1. Dynamic programming: establish a two-dimensional array dp, dp[i][j] represents the editing distance from the first I character substring of word1 to the first j character substring of word2, then:
    1. If word1[i] == word2[j], dp[i][j] = dp[i-1][j-1]
    2. If not, dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1, corresponding to the operation of replacing one character, deleting one character and adding one character respectively.
    3. Add a line and a column of empty characters at the beginning as the initialization status.
class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        n = len(word1)
        m = len(word2)
        
        # A string is empty
        if n * m == 0:
            return n + m
        
        # DP array
        D = [ [0] * (m + 1) for _ in range(n + 1)]
        
        # Boundary state initialization
        for i in range(n + 1):
            D[i][0] = i
        for j in range(m + 1):
            D[0][j] = j
        
        # Calculate all DP values
        for i in range(1, n + 1):
            for j in range(1, m + 1):
                left = D[i - 1][j] + 1
                down = D[i][j - 1] + 1
                left_down = D[i - 1][j - 1] 
                if word1[i - 1] != word2[j - 1]:
                    left_down += 1
                D[i][j] = min(left, down, left_down)
        
        return D[n][m]

Topics: Algorithm