Wilee's Algorithm Notes Sort and Search

1.合并两个有序数组

题目描述:

给定两个有序整数数组 nums1 nums2,将 nums2 合并到 nums1 使得 num1 成为一个有序数组。

说明:

  • 初始化 nums1nums2 的元素数量分别为 mn
  • 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

输出: [1,2,2,3,5,6]

我的答案:插入

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        if m!=0:
            i=0
            for num in nums2:
                flag=0
                while(num>nums1[i]):
                    i+=1
                    if i==m:
                        nums1[i]=num
                        m+=1
                        flag=1
                        break
                if flag==0:
                    for j in range(m,i,-1):
                        nums1[j]=nums1[j-1]
                    nums1[i]=num
                    m+=1
        if m==0:
            for i in range(len(nums2)):
                nums1[i]=nums2[i]

参考答案:

class Solution:
    def merge(self, nums1: 'List[int]', m: 'int', nums2: 'List[int]', n: 'int') -> 'None':
        """
        Do not return anything, modify nums1 in-place instead.
        """
        idx = m+n-1
        i = m-1
        j = n-1
        while j>=0:
            if i <0:
                nums1[idx] = nums2[j]
                j -= 1
            else:
                if nums1[i] > nums2[j]:
                    nums1[idx] = nums1[i]
                    i = i-1
                else:
                    nums1[idx] = nums2[j]
                    j = j-1
            idx = idx-1

 

2.第一个错误的版本

题目描述:

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

示例:

给定 n = 5,并且 version = 4 是第一个错误的版本。

调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true

所以,4 是第一个错误的版本。 

我的答案:二分查找,时间复杂度为o(logn)

class Solution:
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        low=1
        high=n
        while(low

参考答案:二分查找,减少了API调用

class Solution:
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        left_good = 1
        right_bad = n
        while left_good < right_bad:
            check = left_good + (right_bad - left_good) // 2
            if isBadVersion(check):
                right_bad = check
            else:
                left_good = check + 1
        return right_bad

 

3.爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

 

我的答案:递归思想,问题,为什么不能直接用函数递归

解答:空间换时间,直接用递归没有保存答案,造成很多重复计算

class Solution:
    def climbStairs(self, n: int) -> int:
        if n==1:
            return 1
        sumlist=[0]*n
        sumlist[0]=1
        sumlist[1]=2
        for i in range(2,n):
            sumlist[i]=sumlist[i-1]+sumlist[i-2]
        return sumlist[n-1]

参考答案:思路一致

class Solution:
    def climbStairs(self, n: int) -> int:
        dp = [0] * (n+1)
        dp[0] = 1
        dp[1] = 1
        for i in range(2,n+1):
            dp[i] = dp[i-1] + dp[i-2]
        return dp[n]

 

4.买卖股票的最佳时间

题目描述:

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

我的答案:蠢中蠢中蠢中蠢

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if len(prices)>=2:
            i,j=0,1
            profit=[]
            temp=prices[0]
            while(j=temp:
                    temp=prices[j]
                if prices[j]

参考答案:正确利用循环,循环不仅可以重复执行代码,还可以模拟时间的推进

class Solution:
    def maxProfit(self, prices: 'List[int]') -> 'int':
        max_profit = 0
        if prices:
            min_price = prices[0]
            for i in prices:
                if min_price > i:
                    min_price = i
                elif i - min_price > max_profit:
                    max_profit = i - min_price
        return max_profit

 

5.最大子序和

题目描述:

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

我的答案:抠破脑袋没搞出来,蠢中蠢中蠢中蠢中蠢

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        def sum_nums(start,end):
            res=0
            while(start<=end):
                res+=nums[start]
                start+=1
            return res
        
        start,end=0,0
        for i in range(len(nums)):
            if nums[i]>0:
                start,end=i,i
                break
            elif i==len(nums)-1:
                return max(nums)
        pre=end+1
        while(presum_nums(start,end) and pre!=end+1:
                start=pre
                end=pre
                
            elif sum_nums(end+1,pre)>0:
                end=pre
            pre+=1
            
        return sum_nums(start,end)

参考答案:

1.动态规划

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        int sum = 0;
        for (int num : nums) {
            if (sum > 0)
                sum += num;
            else
                sum = num;
            res = Math.max(res, sum);
        }
        return res;
    }
}

or

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
         """
        for i in range(1, len(nums)):
            nums[i]= nums[i] + max(nums[i-1], 0)
        return max(nums)

2.分而治之:java代码,后续自己改成python

class Solution {
    public int maxSubArray(int[] nums) {
        return maxSubArrayPart(nums,0,nums.length-1);
    }
    
    private int maxSubArrayPart(int[] nums,int left,int right){
        if(left==right){
            return nums[left];
        }
        int mid=(left+right)/2;
        return Math.max(
            maxSubArrayPart(nums,left,mid),
            Math.max(
                maxSubArrayPart(nums,mid+1,right),
                maxSubArrayAll(nums,left,mid,right)
            )
        );
    }

    //左右两边合起来求解
    private int maxSubArrayAll(int[] nums,int left,int mid,int right){
        int leftSum=Integer.MIN_VALUE;
        int sum=0;
        for(int i=mid;i>=left;i--){
            sum+=nums[i];
            if(sum>leftSum){
                leftSum=sum;
            }
        }
        sum=0;
        int rightSum=Integer.MIN_VALUE;
        for(int i=mid+1;i<=right;i++){
            sum+=nums[i];
            if(sum>rightSum){
                rightSum=sum;
            }
        }
        return leftSum+rightSum;
    }
}

 

6.打家劫舍

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

我的答案:有个锤子答案,做都做不来,蠢中蠢中蠢中蠢中蠢中蠢

参考答案:好好学,好好看,啥子是动态规划,看清楚

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if nums==[]:
            return 0
        if len(nums)==1:
            return max(nums)
        dp = [0]*len(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[1],nums[0])
        for i in range(2,len(nums)):
            dp[i] = max(dp[i-1],dp[i-2]+nums[i])
            
        return dp[len(nums)-1]

再来个方法,弟弟好好学学

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        last,now = 0,0
        for i in nums:
            last,now = now,max(last+i,now)
        return now

 

7.Shuffle an Array

题目描述:

打乱一个没有重复元素的数组。

示例:

// 以数字集合 1, 2 和 3 初始化数组。
int[] nums = {1,2,3};
Solution solution = new Solution(nums);

// 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。
solution.shuffle();

// 重设数组到它的初始状态[1,2,3]。
solution.reset();

// 随机返回数组[1,2,3]打乱后的结果。
solution.shuffle();

我的答案:No code ,you have nothing to cope with this god damn fuxxking question, reflect on yourself

参考答案:主要问题在于如何从程序的角度完成一个排列组合的问题,洗牌算法,我佛了,中级题目

class Solution(object):

    def __init__(self, nums):
        """
        :type nums: List[int]
        """
        self.nums=nums

    def reset(self):
        """
        Resets the array to its original configuration and return it.
        :rtype: List[int]
        """
        return self.nums

    def shuffle(self):
        """
        Returns a random shuffling of the array.
        :rtype: List[int]
        """
        ans = self.nums[:]                     # copy list
        '''for i in range(len(ans)-1, 0, -1):     # start from end
            j = random.randrange(0, i+1)    # generate random index 
            ans[i], ans[j] = ans[j], ans[i]    # swap'''
        random.shuffle(ans)
        return ans

 

8.最小栈

题目描述:

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。

  • push(x) -- 将元素 x 推入栈中。
  • pop() -- 删除栈顶的元素。
  • top() -- 获取栈顶元素。
  • getMin() -- 检索栈中的最小元素。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

我的答案:一杯茶,一根烟,一道算法做一天,脑壳都做大了,里面还有好多疑问

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack=[]
        self.min_idx_sequence=[]#保证该list的第一个总是最小的元素所在地
        self.up=-1
        
        

    def push(self, x: int) -> None:
        self.stack.append(x)
        self.up+=1
        if self.up==0:
            self.min_idx_sequence.append(self.up)
        else:
            if x=self.stack[self.min_idx_sequence[len(self.min_idx_sequence)-1]]:
                self.min_idx_sequence.append(self.up)
            else:
                for i in range(1,len(self.min_idx_sequence)):    
                    if x < self.stack[self.min_idx_sequence[i]] and x>=self.stack[self.min_idx_sequence[i-1]]:
                        self.min_idx_sequence=self.min_idx_sequence[:i]+[self.up]+self.min_idx_sequence[i:]
                        break

    def pop(self) -> None:
        self.min_idx_sequence.remove(self.up)
        self.stack.pop()
        self.up-=1

    def top(self) -> int:
        return self.stack[self.up]
        

    def getMin(self) -> int:
        return self.stack[self.min_idx_sequence[0]]

参考答案:好好看好好学

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.minstack = []

    def push(self, x: 'int') -> 'None':
        self.stack.append(x)
        if self.minstack == [] or x 'None':
        if self.stack == []:
            return
        else:
            self.stack.pop()
            self.minstack.pop()
        

    def top(self) -> 'int':
        return self.stack[-1]

    def getMin(self) -> 'int':
        return self.minstack[-1]

再来一种方法

import operator
class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.__list = []
        
    def peek(self):
        if len(self.__list) > 0:
            return self.__list[-1]
        
    def push(self, x: int) -> None:
        if len(self.__list) > 0:
            tmp = self.peek()
            self.__list.append(x)
            if tmp > x:
                self.__list.append(x)
            else:
                self.__list.append(tmp)
        else:
            self.__list.append(x)
            self.__list.append(x)
        

    def pop(self) -> None:
        if len(self.__list) > 0:
            self.__list.pop()
            self.__list.pop()
        
        

    def top(self) -> int:
        if len(self.__list) > 0:
            return self.__list[-2]
        return None
        

    def getMin(self) -> int:
        return self.__list[-1]

 

9.FizzBuzz

题目描述:未懂内涵

 

10.计数质数

题目描述:

统计所有小于非负整数 的质数的数量。

示例:

输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。

我的答案:常规列举,超时

参考答案:厄拉多塞筛选法

class Solution:
    def countPrimes(self, n: int) -> int:
            if n < 3:
                return 0     
            else:
                # 首先生成了一个全部为1的列表
                output = [1] * n
                # 因为0和1不是质数,所以列表的前两个位置赋值为0
                output[0],output[1] = 0,0
                 # 此时从index = 2开始遍历,output[2]==1,即表明第一个质数为2,然后将2的倍数对应的索引
                 # 全部赋值为0. 此时output[3] == 1,即表明下一个质数为3,同样划去3的倍数.以此类推.
                for i in range(2,int(n**0.5)+1): 
                    if output[i] == 1:
                        output[i*i:n:i] = [0] * len(output[i*i:n:i])
             # 最后output中的数字1表明该位置上的索引数为质数,然后求和即可.
            return sum(output)

 

11.3的幂

题目描述:

给定一个整数,写一个函数来判断它是否是 3 的幂次方。

示例 1:

输入: 27
输出: true

我的答案:使用了循环

class Solution:
    def isPowerOfThree(self, n: int) -> bool:
        while(n>1):
            n=n/3
        if n==1:
            return True
        else:
            return False

参考答案:

第一种思路:偷鸡,由于int类型中最大的3的幂已知,并且3的幂只有3一个质因子故直接判断

第二种思路:较为巧妙,将十进制转换为三进制然后判断最高位是否为1其他位为0,似乎也需要循环


 

12.罗马数字转整数

题目描述:

罗马数字包含以下七种字符: I, V, X, LCD 和 M

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

我的答案:较为简单,收获是在for循环里面更改迭代数i是无效的,在下一次迭代时还是会恢复为正常值,所以这里使用了while语句

class Solution:
    def romanToInt(self, s: str) -> int:
        d={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
        res=0
        i=0
        while(i=d[s[i+1]]:
                res+=d[s[i]]
            else:
                if s[i]=='I':
                    res+=d[s[i+1]]-1
                elif s[i]=='X':
                    res+=d[s[i+1]]-10
                elif s[i]=='C':
                    res+=d[s[i+1]]-100
                i+=1
            i+=1
        return res

参考答案:代码更简洁可以看一下,不用考虑for循环存在的问题

class Solution:
    def romanToInt(self, s: str) -> int:
        if s == '':
            return 0
        dic = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, \
            'D': 500, 'M': 1000}
        ret = dic[s[0]]
        for i in range(1, len(s)):
            if dic[s[i]] > dic[s[i-1]]:
                ret = ret - dic[s[i-1]] * 2 + dic[s[i]]
            else:
                ret += dic[s[i]]
        return ret

 

13.位1的个数

题目描述:

编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。


我的答案:汇编知识,不断除2取余,为1就加1

class Solution(object):
    def hammingWeight(self, n):
        """
        :type n: int
        :rtype: int
        """
        res=0
        while(n>0):
            if n%2==1:
                res+=1
            n=n//2
        return res

参考答案:汇编知识拉满!

        # count = 0
        # while n:
        #     count += n&1
        #     n >>= 1
        # return count

 

14.汉明距离

题目描述:

两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。

给出两个整数 xy,计算它们之间的汉明距离。

注意:
0 ≤ x, y < 231.

示例:

输入: x = 1, y = 4

输出: 2

解释:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑

上面的箭头指出了对应二进制位不同的位置。

我的答案:参考了上一题的参考答案,汇编知识太顶了

class Solution(object):
    def hammingDistance(self, x, y):
        """
        :type x: int
        :type y: int
        :rtype: int
        """
        res=0
        while max(x,y):
            if x&1!=y&1:
                res+=1
            x >>=1
            y >>=1
        return res

参考答案:好好看好好学

class Solution(object):
    def hammingDistance(self, x, y):
        """
        :type x: int
        :type y: int
        :rtype: int
        """
        return bin(x^y).count("1")

 

15.颠倒二进制位

题目描述:

颠倒给定的 32 位无符号整数的二进制位。

示例 1:

输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
      因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。

我的答案:更像一个字符串处理的问题,重点在于保持位数不变,python内置函数太好用

class Solution:
    # @param n, an integer
    # @return an integer
    def reverseBits(self, n):
        res=bin(n)[2:]
        res=res[::-1]
        if len(res)<32:
            res=res+'0'*(32-len(res))#补齐位数
        return int(res,2)

参考答案:简化了代码之一行搞定

return int(bin(n)[2:].zfill(32)[::-1], 2)

 

16.缺失数字

题目描述:

给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

示例 1:

输入: [3,0,1]
输出: 2

我的答案:哈希集,一个for循环

class Solution(object):
    def missingNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n=len(nums)+1
        s=set(nums)
        for i in range(0,n):
            if i not in s:
                return i

参考答案:好好看看自己是不是蠢了,一个等差数列求和减下来就找到了...

class Solution(object):
    def missingNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        s=len(nums)
        a=s*(s+1)/2
        return a-sum(nums)

 

17.帕斯卡三角形

题目描述:

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。


我的答案:不能一遍过,反省一下自己吧

class Solution(object):
    def generate(self, numRows):
        """
        :type numRows: int
        :rtype: List[List[int]]
        """
        res=[]
        idx=-1
        while(idx=0 and j

参考答案:思路相同,优化一下,不用指针存储当前位置,直接使用-1

class Solution(object):
    def generate(self, numRows):
        """
        :type numRows: int
        :rtype: List[List[int]]
        """
        if numRows == 0:
            return []
        if numRows == 1:
            return [[1]]
        if numRows == 2:
            return [[1],[1,1]]
        res = [[1],[1,1]]
        for i in range(2,numRows):
            newrow = []
            newrow.append(1)
            for j in range(i-1):
                newrow.append(res[-1][j]+res[-1][j+1])
            newrow.append(1)
            res.append(newrow)
        return res

 

18.有效的括号

题目描述:给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

注意空字符串可被认为是有效字符串。


我的答案:主要思路在于维持一个栈

class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        left={'(','{','['}
        stack=[]
        top=-1
        for c in s:
            if c in left:
                stack.append(c)
                top+=1
            elif len(stack)!=0:
                if stack[top]=='(' and c==')':
                    stack.pop()
                    top-=1
                elif stack[top]=='[' and c==']':
                    stack.pop()
                    top-=1
                elif stack[top]=='{' and c=='}':
                    stack.pop()
                    top-=1
                else:
                    return False
            else:
                return False
        return top==-1

参考答案:优化了代码,思路更加清晰

class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        res = []
        for c in s:
            if c in ['(', '[', '{']:
                res.append(c)
            elif c == ')':
                if not res or res.pop() != '(' : return False
            elif c == ']':
                if not res or res.pop() != '[' : return False
            elif c == '}':
                if not res or res.pop() != '{' : return False
            else:
                return False
        return False if res else True

 

你可能感兴趣的:(Wilee's Algorithm Notes Sort and Search)