首页 > 代码库 > leetcode刷题记录(2)

leetcode刷题记录(2)

301. Remove Invalid Parentheses

Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

Note: The input string may contain letters other than the parentheses ( and ).

Examples:

"()())()" -> ["()()()", "(())()"]
"(a)())()" -> ["(a)()()", "(a())()"]
")(" -> [""]

 

解题思路:
  1. 第一遍采用正向遍历数组,将多余的‘)‘去除。用stack来记录到当前位置的‘(‘和‘)‘的数量关系,当出现‘(‘时加1,出现‘)‘时减一。如果stack>=0继续循环,如果stack < 0时,说明到当前位置为止,‘)‘的数量已经超过‘(‘的数量了,需要立即处理,将当前位置之前的不用位置的‘)‘删除,得到不同的字符串后进行递归,当前循环返回。用start_i存储遍历字符串开始的位置,说明之前的字符串都是经过处理后stack=0的;用start_j用来存储上一次删除‘)‘的位置,确保下一次删除‘)‘,是在start_j之后的位置,不会构成重复。
  2. 如果能正常遍历完字符串,说明当前的stack>=0,即‘(‘的数量是大于等于‘)‘的,此时需要将上述过程反过来,将多余的‘(‘删除掉,因此我们将字符串反转后遍历,将函数带有的字符数组改换,原本是[‘(‘,‘)‘],现在换成[‘)‘,‘(‘],完成对‘(‘的删除。由于经过了上一步的过程,所以stack一定不会>0,只有可能<0,即‘(‘的数量大于‘)‘的数量。通过循环后再将字符串反转后加入返回向量中。

刷题记录:

  1. 很重要的一题,NO BUG FREE.

303. Range Sum Query - Immutable

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.

Example:

Given nums = [-2, 0, 3, -5, 2, -1]

sumRange(0, 2) -> 1
sumRange(2, 5) -> -1
sumRange(0, 5) -> -3

 

Note:

  1. You may assume that the array does not change.
  2. There are many calls to sumRange function.

 

解题思路:

  1. 定义一个数组记录sum从0~index的元素求和,那么如果要求i~j的元素和时等于0~j的元素和减去0~(i-1)的元素和。

304. Range Sum Query 2D - Immutable

Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).

技术分享
The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, col2) = (4, 3), which contains sum = 8.

Example:

Given matrix = [
  [3, 0, 1, 4, 2],
  [5, 6, 3, 2, 1],
  [1, 2, 0, 1, 5],
  [4, 1, 0, 1, 7],
  [1, 0, 3, 0, 5]
]

sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12

 

Note:

  1. You may assume that the matrix does not change.
  2. There are many calls to sumRegion function.
  3. You may assume that row1 ≤ row2 and col1 ≤ col2.

 

解题思路:

  1. 构建一个二维数组用来存储当前位置到matrix左上角(即(0,0))所组成的矩形内元素的和。注意添加第一行全为0,第一列全为0,实际构造的数组维度为(m+1)×(n+1),m、n为matrix的维度,为了保持代码的一致性。
  2. 对于(row1,col1)到(row2,col2)的矩形内元素求和,可以等于sum[row2+1][col2+1]-sum[row1][col2+1]-sum[row2+1][col1]+sum[row1][col1]。用大矩形减去两个小矩形再加上重复减去的矩形。

306. Additive Number

Additive number is a string whose digits can form additive sequence.

A valid additive sequence should contain at least three numbers. Except for the first two numbers, each subsequent number in the sequence must be the sum of the preceding two.

For example:
"112358" is an additive number because the digits can form an additive sequence: 1, 1, 2, 3, 5, 8.

1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8

"199100199" is also an additive number, the additive sequence is: 1, 99, 100, 199.

1 + 99 = 100, 99 + 100 = 199

 

Note: Numbers in the additive sequence cannot have leading zeros, so sequence 1, 2, 03 or 1, 02, 3 is invalid.

Given a string containing only digits ‘0‘-‘9‘, write a function to determine if it‘s an additive number.

Follow up:
How would you handle overflow for very large input integers?

 

 
解题思路:
  1. 针对字符串表示的非常大的数字相加,为了防止出现溢出,可以定义一个函数直接实现字符串的相加,并返回结果字符串,完整的避开了变量所能表示范围有限的问题。
  2. 针对各种不同情况下的第一个数和第二个数进行讨论,看看是否满足题设的条件的规律,如果满足就直接返回true,否则继续循环,循环结束返回false。

307. Range Sum Query - Mutable

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.

The update(i, val) function modifies nums by updating the element at index i to val.

Example:

Given nums = [1, 3, 5]

sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8

 

Note:

  1. The array is only modifiable by the update function.
  2. You may assume the number of calls to update and sumRange function is distributed evenly.

 

解题思路:

  1. 如果采用直接向数组中更改值和对范围内元素求和的方法,更改值的时间复杂度为O(1),求和的时间复杂度为O(n)。执行m次操作,平均时间复杂度为O(mn);但是如果使用数状数组(Binary Indexed Tree)来对数组中部分元素的和进行存储,将使修改的时间复杂度变为O(logn),读取和的时间复杂度也变成O(logn),达到一个均衡二者的效果,而将m次操作的时间复杂度变为O(mlogn)。
  2. 假设原数组为nums,长度为n,下标范围为0~(n-1)。那么定义一个长度为n+1的数组sum用来存储nums中特定元素的和,sum的数组是从1开始的,所以nums中的元素下标对应到sum中需要加1。sum存在这样的特点:下标的二进制码的最后连续0的个数决定了当前位置存储和的元素个数,假设当前下标尾数后有k个连续0,那么它存储的就是2^k个元素的和,sum中的下标为i的话,sum[i] = nums[i-1] + nums[i-2]+ ... + nums[i-2^k+1] + nums[i-2^k]。(将sum和nums中下标相差1考虑进去了)。因此每当更改nums中的一个元素时,只需要对包含其求和的那些位置的sum元素进行相应的更改即可,操作次数为logn。对应的位置末尾多一个零(加上一个末位1,即 i += i & -1;)。初始化时,对nums数组进行遍历,将每个元素添在sum中的对应位置。
  3. 在对nums数组中下标0~i范围内元素求解时,从sum数组的下标为(i+1)位置开始,每次将其对应下标多一个零的位置的和加上(减去最末位的1,具体操作为 i -= i & -i;),直到下标为0时停止。

刷题记录:

  1. 存储结构和思路很神奇,需要完全掌握,NO BUG FREE

309. Best Time to Buy and Sell Stock with Cooldown

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)

Example:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

 

 
解题思路:
  1. 定义三个变量sell,buy,rest,分别存储到prices[i]之前(包括prices[i])的三种最新状态下的最大收获。sell是指在下标为i的位置卖出股票,buy是指在i位置买入股票或者在i之前买入股票还没来得及卖(因为如果卖了,那么到i的最新状态就肯定是rest或者sell了),rest指的是在i-1之前已经卖掉然后一直到i都没买入所以最新状态仍然是rest或者在i-1位置时刚刚卖掉股票,所以i位置一定是rest。
  2. 动态规划的关键就是要找前后两种状态的关系式,上述关系通过表达式为:1 sell[i] = buy[i-1] + prices[i]; 2 buy[i] = max(buy[i-1], rest[i-1]-prices[i]); 3 rest[i] = max(rest[i-1], sell[i-1])。通过数学归纳法可以证明上述结论是正确的,最后求max(sell[n-1], res[n-1])的最大值即可,因为得到最大值的方式一定是最新状态为卖出股票或者冷冻日,而不可能是刚买入股票。

刷题记录:

  1. 思路很奇妙,将十分复杂的问题转化成了很简洁的算法,NO BUG FREE

310. Minimum Height Trees

For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.

Format
The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).

You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

Example 1:

Given n = 4edges = [[1, 0], [1, 2], [1, 3]]

        0
        |
        1
       /       2   3

return [1]

Example 2:

Given n = 6edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]

     0  1  2
      \ | /
        3
        |
        4
        |
        5

return [3, 4]

Note:

(1) According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.”

(2) The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

 

 
解题思路:
  1. 此题通过不断删去外层的叶子结点,来得到最短的树的根结点,当所剩下的结点数量<=2时,为根结点返回。
  2. 利用map<int, set<int>>的数据结构来存储与每个结点相连的结点,将set的大小为1的结点加入到存储叶子结点的向量中,当n>2时,删除这个叶子结点,并将与这些叶子结点相连的结点的连接结点set中删除,如果删除后的size为1的话就将其加入到新的存储叶子结点的向量中。然后继续循环,直到n<=2,注意访问set中的元素用迭代器。

刷题记录:

  1. 思路和存储结构都很新颖,NO BUG FREE

312. Burst Balloons

Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent.

Find the maximum coins you can collect by bursting the balloons wisely.

Note: 
(1) You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
(2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example:

Given [3, 1, 5, 8]

Return 167

    nums = [3,1,5,8] --> [3,5,8] -->   [3,8]   -->  [8]  --> []
   coins =  3*1*5      +  3*5*8    +  1*3*8      + 1*8*1   = 167

 

 
解题思路:
  1. 时间复杂度极其高的问题一定要考虑是不是有很多重复计算的工作可以省略,DP算法就能很好的处理这些问题。本题的动态规划我们要逆向考虑,从短的长度延伸到长的序列;在一定长度(从start~end)的序列中,我们要考虑每一个元素作为最后一个元素的可能情况,比较其最大值,在求最后一个元素的coins时,用的是nums[i] * nums[start-1] * nums[end+1],以方便于更大长度的动态引用,因为dp[start][end]=max(dp[start][end],nums[start-1]*nums[i]*nums[end+1]+dp[start][i-1]+dp[i+1][end]),因为dp[start][i-1]和dp[i+1][end]的值在计算时是依赖于nums[i]的值的,所以以上做法能方便之后的计算。

刷题记录:

  1. 动态规划的经典题目,需要熟练掌握思想与写法。NO BUG FREE

leetcode刷题记录(2)