leetcode 刷题-困难

32 最长有效括号
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。

示例 1:

输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:

输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”

题意理解:
有效:可以是不连续的,但是)一定是在前面有与其对应的(
最长:当前面的(都有配对的时候,出现一个)那么这个时候上一次的有效长度就被截断了,下一次计数开始

class Solution:
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        max_ = 0
        now = 0
        temp = []
        for i in range(n):
            if s[i] == '(':
                temp.append(i)
            else:
                if len(temp) == 0:
                    now = i+1
                else:
                    a = temp.pop()
                    if len(temp) == 0:
                        max_ = max(i - now +1,max_)
                    else:
                        max_ = max(i-temp[-1],max_)
        return max_

leetcode 321 拼接最大数:
给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字。现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。

求满足该条件的最大数。结果返回一个表示该最大数的长度为 k 的数组。

说明: 请尽可能地优化你算法的时间和空间复杂度。

示例 1:

输入:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
输出:
[9, 8, 6, 5, 3]
示例 2:

输入:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
输出:
[6, 7, 6, 0, 4]
示例 3:

输入:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
输出:
[9, 8, 9]

思路:首先我们要先明确限制条件是什么?然后来确定功能安排?

  • 限制条件:原数组中的数字相对位置不得改变,这就意味着我们在选取最大数组的时候不能随意按照数字大小来选取,反而要综合考虑数组中数字大小和其位置(因为我们会有输出数组长度限制)
  • 功能安排:
    • 首先我们先要进行分析,假设如例一所示nums1 = [3, 4, 6, 5]
      nums2 = [9, 1, 2, 5, 8, 3],k = 5我们应该怎么选呢?按照功能描述想要找到组成的最大数组,首先我们应该想到是对于给定每个数组选取个数,我们能否找到其最大组成,然后在对选取个数元组进行遍历,最后进行比较选出最大就可以了。所以功能函数就有了
      • 函数 findmax(sum1,k):表示对于数组sum1,找到含有k个元素的保持元素相对位置的数组子集
      • 函数shunxu(sum1,sum2):表示对给定的两个数组,返回这两个数组可以组成的保持元素相对位置的最大数组
    • maxNumber(nums1,nums2,k):完成对所有数组长度选择的遍历,同时完成大小比较
class Solution:
    def findmax(self,sum1,k):#寻找一个数组的最大字串,长度为k
        if k == 0:
            return []
        if len(sum1) == 0:
            return []
        if len(sum1) == k:
                return sum1
        start_range = len(sum1)-k+1
        out = []
        max_num = max(sum1[:start_range])
        max_pos = sum1.index(max_num)
        out.append(max_num)
        next_list = self.findmax(sum1[max_pos+1:],k-1)
        if next_list != None:
            out.extend(next_list)
        return out

    def shunxu(self,sum1,sum2):#对两个数组输出最大组合数组
        if  sum1 == None:
            return sum2
        elif sum2 == None:
            return sum1
        else:
            out = []
            flag = 1
            while flag != 0:
                if sum1 == []:
                    out.extend(sum2)
                    flag = 0                
                    break
                elif sum2 == []:
                    out.extend(sum1)
                    falg = 0                
                    break
                else:
                    if sum1[0] < sum2[0]:
                        out.append(sum2.pop(0))
                        continue
                    elif sum1[0] > sum2[0]:
                        out.append(sum1.pop(0))
                        continue
                    else:
                        i = 0
                        while i < (min(len(sum1),len(sum2))):
                            if sum1[i] > sum2[i]:
                                out.append(sum1.pop(0))
                                break
                            elif sum1[i] < sum2[i]:
                                out.append(sum2.pop(0)) 
                                break
                            else:
                                if i == (min(len(sum1),len(sum2)))-1:
                                    if len(sum1) > len(sum2):
                                        out.append(sum1.pop(0))
                                    elif len(sum1) <= len(sum2):
                                        out.append(sum2.pop(0))
                            i += 1

            return out

    def maxNumber(self, nums1, nums2, k):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :type k: int
        :rtype: List[int]
        """
        max_ = [0]*k
        n1 = len(nums1)
        n2 = len(nums2)
        if n1>n2:
            n1,n2,nums1,nums2 = n2,n1,nums2,nums1

        if n1 < k:
            ls = n1
        else:
            ls = k

        if n2 < k:
            start = k - n2
        else:
            start = 0
        if n2 + n1  == k:
            return self.shunxu(nums1,nums2)
        for i in range(start,ls+1):
            ls_n = k-i           
            list_l = self.findmax(nums1,i)
            list_r = self.findmax(nums2,ls_n)            
            out = self.shunxu(list_l,list_r)
            for i in range(k):
                if out[i] > max_[i]:
                    max_ = out
                    break
                elif out[i] < max_[i]:
                    break
        return max_
 ```
 函数findmax的实现很简单:过程是为了保证最后输出数组的长度为k,且元素保持原来的相对位置,我们使用递归的思想,每一次寻找一个数,这个数字的寻找范围为前len(sum1)-k数,找到之后定位最大数,同时在其后以后开始下一次递归寻找子数组的最大数
 函数shunxu的实现:过程是在两个数组都有元素的情况下通过队列的形式,比较两个数组的第一个数,将较大的那一个数推出,然后循环继续比较。知道最后两个队列有一个为空,将非空队列原样输出即可。
 我在这里有一个陷阱:当队列的两个首位数字相等的时候应该选择哪一个输出?我一开始觉得随便输出,一直没能ac,后来想到还是要比较队列中首位的不同数字,最后将大数所在的那一队列的前面的数字推出。例如sum1 = [1,2,3,4,5,6,7,7,7,9],sum2 = [1,2,3,4,5,6,7,5]在这两个队列中,我们发现0~6位数字均相等,而sum1[7] > sum2[7],所以推出sum1的前7位,最后合并得到out1= [1,2,3,4,5,6,7,7,7,9,1,2,3,4,5,6,7,5],若果随便删,删除sum2的话,那么得到的out2 = [1,2,3,4,5,6,7,5,1,2,3,4,5,6,7,7,7,9],而按照题意,out1 > out2,所以后面的策略是错误的

- 在思考极端情况的时候,一定要考虑0,空,满,相等等极端关系情况,做好条件补充的完整性

leetcode 37 解数独
编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。

![](http://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Sudoku-by-L2G-20050714.svg/250px-Sudoku-by-L2G-20050714.svg.png)

一个数独。

![](http://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Sudoku-by-L2G-20050714_solution.svg/250px-Sudoku-by-L2G-20050714_solution.svg.png)


答案被标成红色。


Note:

给定的数独序列只包含数字 1-9 和字符 '.' 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

思路:采用递归的方式进行,采用DFS深度优先搜索方式,如果没有完成,则改那个值,然后重新填

代码:
```python
class Solution:
    def getnextpoint(self,field):
        for i in range(9):
            for j in range(9):
                if field[i][j] == ".":
                    return [j,i]
        return []
    def isRC(self,x,y,field,num):# 判断这个数是否在行列中
        for i in range(9):
            if field[y][i] == str(num):
                return False
        for j in range(9):
            if field[j][x] == str(num):
                return False
        return True

    def isBox(self,x,y,field, num):
        row,col = (x//3)*3,(y//3)*3
        for i in range(row,row+3):
            for j in range(col,col+3):
                if field[j][i] == str(num):
                    return False
        return True


    def DFS(self,board):
        nextpoint = self.getnextpoint(board)
        if not nextpoint:
            return True
        for i in range(1,10):
            if self.isRC(nextpoint[0],nextpoint[1],board,i) and self.isBox(nextpoint[0],nextpoint[1],board,i):
                board[nextpoint[1]][nextpoint[0]] = str(i)
                #print(i)
                if self.DFS(board):
                    return True
                board[nextpoint[1]][nextpoint[0]] = '.'

    def solveSudoku(self, board):
        """
        :type board: List[List[str]]
        :rtype: void Do not return anything, modify board in-place instead.
        """
        self.DFS(board)





<div class="se-preview-section-delimiter"></div>
  • 42 接雨水I

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
思路:我们可以先找到最高点,然后利用最高点分成左右两部分,利用指针分别从左和右向中间移动,同时招次高峰,来进行计算
代码如下:

class Solution:

    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        maxheight = 0
        max_index = 0
        cnt = 0
        #遍历所有点,找到第一次出现最高峰的位置
        for i in range(1,len(height)):
            if height[i] > height[max_index]:
                max_index = i
        #从左到右找坑
        for i in range(max_index):
            if maxheight < height[i]:
                maxheight = height[i]
            else:
                cnt += maxheight - height[i]
        maxheight = 0
        #从右到左找坑
        for i in range(len(height)-1,max_index,-1):
            if maxheight < height[i]:
                maxheight = height[i]
            else:
                cnt += maxheight - height[i]
        return cnt





<div class="se-preview-section-delimiter"></div>
  • 407 接雨水 II
    给定一个m x n的矩阵,其中的值均为正整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。

说明:

m 和 n 都是小于110的整数。每一个单位的高度都大于0 且小于 20000。

示例:

给出如下 3x6 的高度图:
[
[1,4,3,1,3,2],
[3,2,1,3,2,4],
[2,3,3,2,3,1]
]

返回 4。

填满之后是

思路:我们想要填满里面坑里的水,那么我们就要知道其四周的水的高度,所以按照这个思路,我们代码在搜索的时候应该要从外围向里面搜索
创建一个完成之后的水坑的表示数组fmax,除了外围点外其余内部点对应值均为无限大(在python中使用float(‘inf’)表示):
使用了广度优先搜索的思路。我们可以先构造水坑最外围一圈的坑高,因为最外围肯定是不需要添水的,所以我们先将heightMap的最外围数赋值给fmax的对应位置,同时将其外围点压入一个队列中,这个队列表示的就是围墙的位置。
代码

class Solution:
    def trapRainWater(self, heightMap):
        """
        :type heightMap: List[List[int]]
        :rtype: int
        """

        m = len(heightMap)
        if m  <= 1: 
            return 0
        n = len(heightMap[0])

        queue = []
        fmax = [[float('inf') for i in range(n)]for i in range(m)]
        #找到边界
        for i in range(m):
            for j in range(n):
                if i in (0,m-1) or j in (0,n-1):
                    fmax[i][j] = heightMap[i][j]
                    queue.append((i,j))
        #print(fmax)
        while queue: #
            y,x = queue.pop(0)
            for dy,dx in zip([0,1,0,-1],[1,0,-1,0]):
                ny,nx = y+dy,x+dx
                if ny <= 0 or nx <= 0 or ny >= m-1 or nx >= n-1:
                    continue
                arounflimit = max(fmax[y][x],heightMap[ny][nx])
                #print(arounflimit)
                if fmax[ny][nx] > arounflimit:
                    fmax[ny][nx] = arounflimit
                    queue.append((ny,nx))
        return sum(fmax[i][j] - heightMap[i][j] for i in range(m) for j in range(n))

- 407 接雨水 II
给定一个m x n的矩阵,其中的值均为正整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。

说明:

m 和 n 都是小于110的整数。每一个单位的高度都大于0 且小于 20000。

示例:

给出如下 3x6 的高度图:
[
  [1,4,3,1,3,2],
  [3,2,1,3,2,4],
  [2,3,3,2,3,1]
]

返回 4。
![](https://i-blog.csdnimg.cn/blog_migrate/26f1a8852f2fa3440a65d4b7945a2473.png)
填满之后是
![](https://i-blog.csdnimg.cn/blog_migrate/d165246facd58695779e3fa4b295a9ea.png)

思路:我们想要填满里面坑里的水,那么我们就要知道其四周的水的高度,所以按照这个思路,我们代码在搜索的时候应该要从外围向里面搜索
创建一个完成之后的水坑的表示数组fmax,除了外围点外其余内部点对应值均为无限大(在python中使用float('inf')表示):
使用了广度优先搜索的思路。我们可以先构造水坑最外围一圈的坑高,因为最外围肯定是不需要添水的,所以我们先将heightMap的最外围数赋值给fmax的对应位置,同时将其外围点压入一个队列中,这个队列表示的就是围墙的位置。
代码
```python
class Solution:
    def trapRainWater(self, heightMap):
        """
        :type heightMap: List[List[int]]
        :rtype: int
        """

        m = len(heightMap)
        if m  <= 1: 
            return 0
        n = len(heightMap[0])

        queue = []
        fmax = [[float('inf') for i in range(n)]for i in range(m)]
        #找到边界
        for i in range(m):
            for j in range(n):
                if i in (0,m-1) or j in (0,n-1):
                    fmax[i][j] = heightMap[i][j]
                    queue.append((i,j))
        #print(fmax)
        while queue: #
            y,x = queue.pop(0)
            for dy,dx in zip([0,1,0,-1],[1,0,-1,0]):
                ny,nx = y+dy,x+dx
                if ny <= 0 or nx <= 0 or ny >= m-1 or nx >= n-1:
                    continue
                arounflimit = max(fmax[y][x],heightMap[ny][nx])
                #print(arounflimit)
                if fmax[ny][nx] > arounflimit:
                    fmax[ny][nx] = arounflimit
                    queue.append((ny,nx))
        return sum(fmax[i][j] - heightMap[i][j] for i in range(m) for j in range(n))




<div class="se-preview-section-delimiter"></div>

leetcode 68 文本左右对齐
题目描述:
给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。

你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ’ ’ 填充,使得每行恰好有 maxWidth 个字符。

要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。

文本的最后一行应为左对齐,且单词之间不插入额外的空格。

说明:

单词是指由非空格字符组成的字符序列。
每个单词的长度大于 0,小于等于 maxWidth。
输入单词数组 words 至少包含一个单词。
例:

输入:
words = [“This”, “is”, “an”, “example”, “of”, “text”, “justification.”]
maxWidth = 16
输出:
[
“This is an”,
“example of text”,
“justification. ”
]
示例 2:

输入:
words = [“What”,”must”,”be”,”acknowledgment”,”shall”,”be”]
maxWidth = 16
输出:
[
“What must be”,
“acknowledgment “,
“shall be ”
]
解释:

- 注意最后一行的格式应为 "shall be    " 而不是 "shall     be",
-  因为最后一行应为左对齐,而不是左右两端对齐。       
- 第二行同样为左对齐,这是因为这行只包含一个单词。

示例 3:

输入:
words = [“Science”,”is”,”what”,”we”,”understand”,”well”,”enough”,”to”,”explain”,
“to”,”a”,”computer.”,”Art”,”is”,”everything”,”else”,”we”,”do”]
maxWidth = 20
输出:
[
“Science is what we”,
“understand well”,
“enough to explain to”,
“a computer. Art is”,
“everything else we”,
“do ”
]

解题思路:
看到这道题,我的想法是将问题分解为两个步骤:
步骤一:找出每一个符合长度的组合
步骤二:对每一个符合条件的组合进行字符串整合(注意:一定要看清楚题目中的解释)

步骤的具体思路:
步骤一思路:使用while循环,来依次寻找符合条件的字符串组合,保证这一过程的时间复杂度为O(n),最好不要使用for循环,如果使用for循环会使得时间复杂度增大

步骤二思路:注意这里的间隔是尽可能的均分,同时在无法均分的时候,尽可能使相邻两个间隔的空格数差值最小,同时保证左边的空格数要比右边的大,所以我的思路时递归的类似思想(实现并非递归)。每一次循环进行均分判断,如果可以均分则直接均分剩余间隔,如果无法均分则剩余间隔最左间隔空格数 space_left = n // d + 1(n此时需要填充的空格数,d此时需要填充的间隔数)

python代码如下
“`


leetcode 68 文本左右对齐
题目描述:
给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。

你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。

要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。

文本的最后一行应为左对齐,且单词之间不插入额外的空格。

说明:

单词是指由非空格字符组成的字符序列。
每个单词的长度大于 0,小于等于 maxWidth。
输入单词数组 words 至少包含一个单词。
例:

输入:
words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
输出:
[
   "This    is    an",
   "example  of text",
   "justification.  "
]
示例 2:

输入:
words = ["What","must","be","acknowledgment","shall","be"]
maxWidth = 16
输出:
[
  "What   must   be",
  "acknowledgment  ",
  "shall be        "
]
解释: 

    - 注意最后一行的格式应为 "shall be    " 而不是 "shall     be",
    -  因为最后一行应为左对齐,而不是左右两端对齐。       
    - 第二行同样为左对齐,这是因为这行只包含一个单词。
示例 3:

输入:
words = ["Science","is","what","we","understand","well","enough","to","explain",
         "to","a","computer.","Art","is","everything","else","we","do"]
maxWidth = 20
输出:
[
  "Science  is  what we",
  "understand      well",
  "enough to explain to",
  "a  computer.  Art is",
  "everything  else  we",
  "do                  "
]

解题思路:
看到这道题,我的想法是将问题分解为两个步骤:
步骤一:找出每一个符合长度的组合
步骤二:对每一个符合条件的组合进行字符串整合(注意:一定要看清楚题目中的解释)

步骤的具体思路:
步骤一思路:使用while循环,来依次寻找符合条件的字符串组合,保证这一过程的时间复杂度为O(n),最好不要使用for循环,如果使用for循环会使得时间复杂度增大

步骤二思路:注意这里的间隔是尽可能的均分,同时在无法均分的时候,尽可能使相邻两个间隔的空格数差值最小,同时保证左边的空格数要比右边的大,所以我的思路时递归的类似思想(实现并非递归)。每一次循环进行均分判断,如果可以均分则直接均分剩余间隔,如果无法均分则剩余间隔最左间隔空格数 space_left = n // d + 1(n此时需要填充的空格数,d此时需要填充的间隔数)

python代码如下
```python
class Solution:
    def change(self,s,maxWidth):
        #print(s)
        if len(s) == 1:
            out = s[0] + ' '*(maxWidth - len(s[0]))
            return out
        space = len(s)-1
        need = maxWidth
        for i in range(len(s)):
            need -= len(s[i])
        out_space = []
        while space > 0:
            if need%space == 0:
                out_space.extend([need//space]*space)
                break
            else:
                now = need//space + 1
                out_space.append(now)
                need -= now
                space -= 1
        print(out_space)
        print(len(s))
        out = s[0]
        for i in range(1,len(s)):
            out += ' '*out_space[i-1] + s[i]
        print(out)
        return out    

    def fullJustify(self, words, maxWidth):
        """
        :type words: List[str]
        :type maxWidth: int
        :rtype: List[str]
        """
        pt = []
        i = 1
        line = [words[0]]
        line_lenth = len(words[0])
        while i < len(words):
            #print(len(words[i])+1+line_lenth )
            if len(words[i])+1+line_lenth <= maxWidth:
                line.append(words[i])
                line_lenth += len(words[i])+1
                i += 1
                #print('line is {}'.format(line))
            else:
                #print('print line is {}'.format(line))
                pt.append(line)
                line = [words[i]]

                line_lenth = len(words[i])
                i += 1


        for i in range(len(pt)):
            pt[i] = self.change(pt[i],maxWidth)

        if len(line)>0:
            sheng = maxWidth - line_lenth
            ss = line[0]
            for i in range(1,len(line)):
                ss += ' '+ line[i]
            ss += ' '*sheng
        pt.append(ss)


        return pt
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值