Question 256 Paint House

The description of the question is in the following link:

https://leetcode.com/problems/paint-house/

My code

class Solution:
    def minCost(self, costs: List[List[int]]) -> int:
        if len(costs) == 0:
            return 0
        else:
            RedList = [0]*len(costs)
            BlueList = [0]*len(costs)
            GreenList = [0]*len(costs)
            RedList[0] = costs[0][0];
            BlueList[0] = costs[0][1];
            GreenList[0] = costs[0][2];
            for i in range(1,len(costs)):
                RedList[i]  = min(BlueList[i-1]+costs[i][0], GreenList[i-1]+costs[i][0])
                BlueList[i] = min(RedList[i-1]+costs[i][1], GreenList[i-1]+costs[i][1])
                GreenList[i]= min(RedList[i-1]+costs[i][2], BlueList[i-1]+costs[i][2])
            Min1 = min(RedList[-1],BlueList[-1])
            Min2 = min(Min1, GreenList[-1])
            return Min2

Explanation:

Here for each house, we have three choices: blue, green or the red, for each choice, we have different minimum costs that we can have in order to choose that specific color (green, red or blue). We do not know which one would provide the best choice, so we can  have three different routines: Red List gives the minimum cost for choosing red this time, and similar for other lists. For the best answer, we just need to find the minimum cost on choosing three different colors at the end of the list.

Question 1025 Divisor Game

The description of the question is in the following link:

https://leetcode.com/problems/divisor-game/

My Code:

def divisorGame(self, N: int) -> bool:
        if N ==1:
            return False
        else:
            ResultList = [0]*(N+1)
            ResultList[0] = "Empty"
            ResultList[1] = "Lose"
            ResultList[2] = "Win" #Here win means that whoever takes this number has a strategy to win with 100%
            for i in range(3,N+1):
                LoseIndicator = 0
                TestNumber = math.ceil(i/2)
                for j in range(1,TestNumber+1):
                    if i/j == i//j:
                        if ResultList[i-j] == "Lose":
                            LoseIndicator +=1

                if LoseIndicator == 0:
                    ResultList[i] = "Lose"
                else:
                    ResultList[i] = "Win"
            if ResultList[N] =="Win":
                return True
            else:
                return False

Explanation: The win and lose here denotes if the one who chooses this number may win or not. As they are all optimal player, the only time they can win is that under all the situation (with all divisor x), the only choice for the other guy is win, otherwise they may choose the one that lead the opponent to lose.

 

 

Question 647 palindromic substrings

Description:

https://leetcode.com/problems/palindromic-substrings/

My Code

class Solution:
    def countSubstrings(self, s: str) -> int:
        InputList = [[s[i] for i in range(len(s))]]
        TotalNum = len(s)
        for i in range(len(s)-1):
            OldList = InputList[i]
            NewList = []
            for j in range(i+1,len(s)):
                NewString = OldList[j-i-1]+ s[j]
                NewList.append(NewString)
                if NewString  == NewString[::-1]:
                    TotalNum +=1
            InputList.append(NewList)
        return TotalNum

Explain:

Take all possible out and then test one by one. Saving time by using extra storage space.

 

Question 13 Roman to Integer

The description of the question is in the following link:

https://leetcode.com/problems/roman-to-integer/

My Code:

class Solution:
    def romanToInt(self, s: str) -> int:
        RomanToIntegerDict = {
            "I": 1,
            "V": 5,
            "X": 10,
            "L": 50,
            "C": 100,
            "D": 500,
            "M": 1000,
        }
        if len(s) ==1:
            return RomanToIntegerDict[s[0]]
        else:
            OutputNum = 0
            i = 0
            while i< len(s):
                if i == len(s) -1:
                    OutputNum += RomanToIntegerDict[s[i]]
                    return OutputNum
                else:
                    KeyThis = s[i]
                    KeyNext = s[i+1]
                    if RomanToIntegerDict[KeyThis]< RomanToIntegerDict[KeyNext]:
                        OutputNum += RomanToIntegerDict[KeyNext]-RomanToIntegerDict[KeyThis]
                        i+=1
                    else:
                        OutputNum += RomanToIntegerDict[KeyThis]
                    i+=1
            return OutputNum

Explanation: the key point is to know how to read the roman number. Whenever the number behind you is larger than the value you have now, it means that you need to take the subtraction between the number later and the number you have now. Next point is to be careful with the last element in the string.

Question 523 Continuous SubArray Sum

The description of the code is in the following link

 

My Code

class Solution:
    def checkSubarraySum(self, nums: List[int], k: int) -> bool:
        if len(nums) <2:
            return False
        else:
            if k == 0:
                InputList= nums[0:2]
                if sum(InputList)  == 0:
                    return True
                else:
                    SumList = [[sum(InputList[i:len(InputList)]) for i in range(len(InputList))]]
                    SumList = [[0],[0]]+SumList # To get the save for the list with length 2
                    for i in range(2, len(nums)):
                        NewList = []
                        for j in range(i):
                            NewSum = nums[i]+SumList[i][j]
                            if NewSum == 0:
                                return True
                            NewList.append(NewSum)
                        NewList.append(nums[i])
                        SumList.append(NewList)
                    return False
            else:
                InputList = nums[0:2];
                if sum(InputList) % k ==0:
                    return True
                else:
                    SumList = [[sum(InputList[i:len(InputList)]) for i in range(len(InputList))]]
                    SumList = [[0],[0]]+SumList # To get the save for the list with length 2
                    for i in range(2, len(nums)):
                        NewList = []
                        for j in range(i):
                            NewSum = nums[i]+SumList[i][j]
                            if NewSum %k  == 0:
                                return True
                            NewList.append(NewSum)
                        NewList.append(nums[i])
                        SumList.append(NewList)
                return False

Explanation: The key point is still doing it brutally. We check all the possible sum and whenever we encounter find there is a full division, we return true, otherwise we return false. Here we use one extra array to improve the time complexity, otherwise it is going to be n^3, now it is n^2

 

Another Approach: Using Hash Table (The Solution is not clearly clarified, need to do some further reading)

Question 122. Best Time to Buy and Sell Stock II

the description of the question is in the following link

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/

My code

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if len(prices) ==0 or len(prices) ==1:
            return 0
        else:
            TotalProfit = 0
            i = 0
            while i < len(prices)-1:
                Buy = prices[i]
                Sell = prices[i+1]
                PriceDiff = Sell - Buy 
                TotalProfit  += max(PriceDiff,0)
                i+=1
            return TotalProfit

We can see the total profit as a cumulative daily return, the only difference is that whenever we encounter a negative daily return, we ignore the loss part. Hence we just need to add all the positive returns.

Question 121 Best Time to Buy and Sell Stock

The description of the question is given in the following link:

https://leetcode.com/problems/best-time-to-buy-and-sell-stock/

My code:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if len(prices) == 0:
            return 0
        else:
            Maximum = 0
            Buy = prices[0]
            Index = 1
            i= 1
            while(i<len(prices)):
                Sell = prices[i]
                profit = Sell-Buy
                if profit< 0:
                    Buy = Sell
                Maximum = max(profit, Maximum)
                i +=1
            return Maximum

Explanation:

This code is straightforward: We start from first element as buy in . Whenever we have a negative profit, it means that we have a lower price later, hence for any profit we have later, buy in with the lower price will definitely give the larger profit, that’s why we substitute the buy with sell here. Then for each time we compare the profit we have with the previous profit, which gives the maximum.

 

 

 

 

 

Question 96. Unique Binary Search Trees

The description of the question is in the following link:

 

My code:

class Solution:
    def numTrees(self, n: int) -> int:
        if n ==1:
            return 1
        elif n ==2 :
            return 2
        else:
            TotalNumberList = [1]*(1+n)
            for Length in range(2,n+1):
                TotalSum = 0
                for Index in range(Length):
                    NumberDevideByThisIndex = TotalNumberList[Index]*TotalNumberList[Length-1-Index]
                    TotalSum += NumberDevideByThisIndex
                TotalNumberList[Length] = TotalSum
            return TotalNumberList[n]

Explanation: It actually does not matter if the value is from 1 to n or otherwise, as long as they are sorted by some order. The logic is that for each particular value we choose, the list is divided into two parts: left list and right list. We just need to multiply the number in the left list and right list to get the total number of trees we have for this particular number. As for all the ordered list with the same length, they all have the same number of trees, hence we just need to start from the number of trees with one and zero, then gradually calculate from one to n and return the nth one in the list.

Question 91 Decode Ways

Question:

https://leetcode.com/problems/decode-ways/

 

My code

class Solution:
    def numDecodings(self, s: str) -> int:
# First we finish the part that the length of the string is 1
        if len(s) ==1:
            if int(s[0])== 0:
                return 0
            else:
                return 1
        else: # we then finish the part which has length larger than 1
            if int(s[0]) == 0:
                Mat = [0]*len(s)
            else:
                Mat = [1]*len(s)
            for StringNum in range(1,len(s)):
                if int(s[StringNum-1]) == 0:
                    if int(s[StringNum]) == 0:
                        Mat[StringNum] = 0
                    else:
                        if StringNum ==1:
                            Mat[StringNum]= 0
                        else:
                            Mat[StringNum] = Mat[StringNum-1] 
                elif int(s[StringNum-1])==1:
                    if int(s[StringNum])==0:
                        if StringNum == 1:
                            Mat[StringNum] = 1
                        else:
                            Mat[StringNum] = Mat[StringNum-2]
                    else:
                        if StringNum ==1:
                            Mat[StringNum] = 2
                        else:
                            Mat[StringNum] = Mat[StringNum-1]+Mat[StringNum-2]
                elif int(s[StringNum-1]) ==2:
                    if int(s[StringNum]) == 0:
                        if StringNum ==1:
                            Mat[StringNum] = 1
                        else:
                            Mat[StringNum] = Mat[StringNum-2]
                    elif int(s[StringNum]) >=7:
                        if StringNum ==1:
                            Mat[StringNum] =1
                        else:
                            Mat[StringNum] = Mat[StringNum-1]
                    else:
                        if StringNum ==1:
                            Mat[StringNum] = 2
                        else:
                            Mat[StringNum] = Mat[StringNum-1]+ Mat[StringNum-2]
                else:
                    if int(s[StringNum]) == 0:
                        Mat[StringNum] = 0
                    else:
                        if StringNum == 1:
                            Mat[StringNum] = 1
                        else:
                            Mat[StringNum] = Mat[StringNum-1]
        
        return Mat[len(s)-1]

Explanation:

The Structure of the code is a little difficult to explain in words. There will be (If I do not forget) a full chart to illustrate the whole idea.

Question 70 Climbing Stairs

The description of the question is in the following link:

https://leetcode.com/problems/climbing-stairs/

My Code:

class Solution:
    def climbStairs(self, n: int) -> int:
        Ladder = [1]*n;
        if n ==1: 
            return 1;
        else:
            Ladder[1] = 2;
            for LadNum in range(2,n):
                Ladder[LadNum] = Ladder[LadNum-1]+Ladder[LadNum -2]
            return Ladder[n-1]

Explanation:

The idea is clear: the only way to reach the nth ladder is that going from n-1th ladder with 1 step and n-2th ladder with 2 steps. So we just need to sum the number of steps to reach these two ladders to get the step to reach nth ladder. Just need to be very careful about some special situation and initialisation.