面试经典150题

合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2，另有两个整数 m 和 n ，分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中，使合并后的数组同样按 非递减顺序 排列。

注意：最终，合并后数组不应由函数返回，而是存储在数组 nums1 中。为了应对这种情况，nums1 的初始长度为 m + n，其中前 m 个元素表示应合并的元素，后 n 个元素为 0 ，应忽略。nums2 的长度为 n 。

示例 1：

Copy
输入：nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出：[1,2,2,3,5,6]
解释：需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ，其中斜体加粗标注的为 nums1 中的元素。

示例 2：

Copy
输入：nums1 = [1], m = 1, nums2 = [], n = 0
输出：[1]
解释：需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3：

Copy
输入：nums1 = [0], m = 0, nums2 = [1], n = 1
输出：[1]
解释：需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意，因为 m = 0 ，所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

Copy
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.
"""
i, j = m - 1, n - 1
k = len(nums1) - 1
while (i >= 0 and j >= 0):
if (nums1[i] > nums2[j]):
nums1[k] = nums1[i]
i -= 1
else:
nums1[k] = nums2[j]
j -= 1
k -= 1
if (i == -1):
for i in range(0, j+1):
nums1[i] = nums2[i]

移除元素

给你一个数组 nums 和一个值 val，你需要 原地 移除所有数值等于 val 的元素，并返回移除后数组的新长度。

不要使用额外的数组空间，你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1：

Copy
输入：nums = [3,2,2,3], val = 3
输出：2, nums = [2,2]
解释：函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如，函数返回的新长度为 2 ，而 nums = [2,2,3,3] 或 nums = [2,2,0,0]，也会被视作正确答案。

示例 2：

Copy
输入：nums = [0,1,2,2,3,0,4,2], val = 2
输出：5, nums = [0,1,4,0,3]
解释：函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

Copy
class Solution:
def removeElement(self, nums: list[int], val: int) -> int:
i, j = 0, len(nums)
while (i < j):
if (nums[i] == val):
j -= 1
nums[i] = nums[j]
else:
i += 1
return j

删除有序数组中的重复项

给你一个 升序排列 的数组 nums ，请你 ** 原地** 删除重复出现的元素，使每个元素 只出现一次 ，返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ，你需要做以下事情确保你的题解可以被通过：

更改数组 nums ，使 nums 的前 k 个元素包含唯一元素，并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。

返回 k 。

示例 1：

Copy
输入：nums = [1,1,2]
输出：2, nums = [1,2,_]
解释：函数应该返回新的长度 2 ，并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2：

Copy
输入：nums = [0,0,1,1,1,2,2,3,3,4]
输出：5, nums = [0,1,2,3,4]
解释：函数应该返回新的长度 5 ， 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

Copy
class Solution:
def removeDuplicates(self, nums: list[int]) -> int:
j = 0
for i in range(1, len(nums)):
if (nums[i] != nums[j]):
nums[j + 1] = nums[i]
j += 1
return j + 1

删除有序数组中的重复项 II

给你一个有序数组 nums ，请你 ** 原地** 删除重复出现的元素，使得出现次数超过两次的元素只出现两次 ，返回删除后数组的新长度。

不要使用额外的数组空间，你必须在 原地 修改输入数组 并在使用 O (1) 额外空间的条件下完成。

示例 1：

Copy
输入：nums = [1,1,1,2,2,3]
输出：5, nums = [1,1,2,2,3]
解释：函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。

示例 2：

Copy
输入：nums = [0,0,1,1,1,1,2,3,3]
输出：7, nums = [0,0,1,1,2,3,3]
解释：函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 不需要考虑数组中超出新长度后面的元素。

Copy
class Solution:
def removeDuplicates(self, nums: list[int]) -> int:
if (len(nums) <= 2):
return len(nums)
i = 1
for j in range(2, len(nums)):
if (nums[j] != nums[i] or nums[j] == nums[i] and nums[j] != nums[i-1]):
nums[i + 1] = nums[j]
i += 1
return i + 1

多数元素

给定一个大小为 n 的数组 nums ，返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的，并且给定的数组总是存在多数元素。

示例 1：

Copy
输入：nums = [3,2,3]
输出：3

示例 2：

Copy
输入：nums = [2,2,1,1,1,2,2]
输出：2

Copy
class Solution:
def majorityElement(self, nums: list[int]) -> int:
count = 0
res = nums[0]
for num in nums:
if (count == 0 or res == num):
res = num
count += 1
else:
count -= 1
return res

轮转数组

给定一个整数数组 nums，将数组中的元素向右轮转 k 个位置，其中 k 是非负数。

示例 1:

Copy
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

Copy
输入：nums = [-1,-100,3,99], k = 2
输出：[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

Copy
class Solution:
def rotate(self, nums: list[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def reverse(nums, start, end):
while (start < end):
nums[start], nums[end] = nums[end], nums[start]
start += 1
end -= 1
k = k % len(nums)
reverse(nums, 0, len(nums) - k - 1)
reverse(nums, len(nums) - k, len(nums)-1)
reverse(nums, 0, len(nums)-1)

买卖股票的最佳时机

给定一个数组 prices ，它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票，并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润，返回 0 。

示例 1：

Copy
输入：[7,1,5,3,6,4]
输出：5
解释：在第 2 天（股票价格 = 1）的时候买入，在第 5 天（股票价格 = 6）的时候卖出，最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格；同时，你不能在买入前卖出股票。

示例 2：

Copy
输入：prices = [7,6,4,3,1]
输出：0
解释：在这种情况下, 没有交易完成, 所以最大利润为 0。

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

跳跃游戏

给定一个非负整数数组 nums ，你最初位于数组的 第一个下标 。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1：

Copy
输入：nums = [2,3,1,1,4]
输出：true
解释：可以先跳 1 步，从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2：

Copy
输入：nums = [3,2,1,0,4]
输出：false
解释：无论怎样，总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 ， 所以永远不可能到达最后一个下标。

Copy
class Solution:
def canJump(self, nums: list[int]) -> bool:
n, rightmost = len(nums), 0
for i in range(n):
if (i <= rightmost):
rightmost = max(rightmost, i + nums[i])
if (rightmost >= n-1):
return True
return False

跳跃游戏 II

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说，如果你在 nums[i] 处，你可以跳转到任意 nums[i + j] 处:

0 <= j <= nums[i]

i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。

示例 1:

Copy
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置，跳 1 步，然后跳 3 步到达数组的最后一个位置。

示例 2:

Copy
输入: nums = [2,3,0,1,4]
输出: 2

Copy
class Solution:
def jump(self, nums: list[int]) -> int:
n = len(nums)
rightmost, end, step = 0, 0, 0
for i in range(n-1):
if (rightmost >= i):
rightmost = max(rightmost, i + nums[i])
if (i == end):
end = rightmost
step += 1
return step

除自身以外数组的乘积

给你一个整数数组 nums，返回 数组 answer ，其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

请 ** 不要使用除法，** 且在 O(*n*) 时间复杂度内完成此题。

示例 1:

Copy
输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

Copy
输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

Copy
class Solution:
def productExceptSelf(self, nums: list[int]) -> list[int]:
left = [1 for _ in nums]
right = [1 for _ in nums]
for i in range(1, len(nums)):
left[i] = nums[i-1] * left[i-1]
for i in range(len(nums)-2, -1, -1):
right[i] = nums[i+1] * right[i+1]
return [left[i] * right[i] for i in range(len(nums))]

接雨水

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

示例 1：

Copy
输入：height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出：6
解释：上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图，在这种情况下，可以接 6 个单位的雨水（蓝色部分表示雨水）。

示例 2：

Copy
输入：height = [4,2,0,3,2,5]
输出：9

Copy
class Solution:
def trap(self, height: list[int]) -> int:
if (len(height) <= 2):
return 0
lmax = [0 for _ in height]
rmax = [0 for _ in height]
for i in range(1, len(height)-1):
lmax[i] = max(lmax[i-1], height[i-1])
for i in range(len(height)-2, 0, -1):
rmax[i] = max(rmax[i+1], height[i+1])
res = 0
for i in range(1, len(height) - 1):
if (min(lmax[i], rmax[i]) - height[i] > 0):
res += (min(lmax[i], rmax[i]) - height[i])
return res

罗马数字转整数

罗马数字包含以下七种字符: I， V， X， L，C，D 和 M。

Copy
字符 数值
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。

给定一个罗马数字，将其转换成整数。

示例 1:

Copy
输入: s = "III"
输出: 3

示例 2:

Copy
输入: s = "IV"
输出: 4

示例 3:

Copy
输入: s = "IX"
输出: 9

示例 4:

Copy
输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.

示例 5:

Copy
输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.

Copy
class Solution:

SYMBOL_VALUES = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000,
}

def romanToInt(self, s: str) -> int:
ans = 0
n = len(s)
for i, ch in enumerate(s):
val = Solution.SYMBOL_VALUES[ch]
if ((i < n-1) and val < Solution.SYMBOL_VALUES[s[i+1]]):
ans -= val
else:
ans += val
return ans

整数转罗马数字

罗马数字包含以下七种字符： I， V， X， L，C，D 和 M。

Copy
字符 数值
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。

给你一个整数，将其转为罗马数字。

示例 1:

Copy
输入: num = 3
输出: "III"

示例 2:

Copy
输入: num = 4
输出: "IV"

示例 3:

Copy
输入: num = 9
输出: "IX"

示例 4:

Copy
输入: num = 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.

示例 5:

Copy
输入: num = 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.

Copy
class Solution:

VALUE_SYMBOLS = [
(1000, "M"),
(900, "CM"),
(500, "D"),
(400, "CD"),
(100, "C"),
(90, "XC"),
(50, "L"),
(40, "XL"),
(10, "X"),
(9, "IX"),
(5, "V"),
(4, "IV"),
(1, "I"),
]

def intToRoman(self, num: int) -> str:
res = []
for val, symbol in Solution.VALUE_SYMBOLS:
while (num >= val):
res.append(symbol)
num -= val
if (num == 0):
break
return ''.join(res)

最后一个单词的长度

给你一个字符串 s，由若干单词组成，单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。

单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

示例 1：

Copy
输入：s = "Hello World"
输出：5
解释：最后一个单词是“World”，长度为5。

示例 2：

Copy
输入：s = " fly me to the moon "
输出：4
解释：最后一个单词是“moon”，长度为4。

示例 3：

Copy
输入：s = "luffy is still joyboy"
输出：6
解释：最后一个单词是长度为6的“joyboy”。

Copy
class Solution:
def lengthOfLastWord(self, s: str) -> int:
r = len(s)-1
while (s[r] == ' '):
r -= 1
i = r
while (i >= 0 and s[i] != ' '):
i -= 1
return r-i

最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀，返回空字符串 ""。

示例 1：

Copy
输入：strs = ["flower","flow","flight"]
输出："fl"

示例 2：

Copy
输入：strs = ["dog","racecar","car"]
输出：""
解释：输入不存在公共前缀。

Copy
class Solution:
def longestCommonPrefix(self, strs: list[str]) -> str:
if (len(strs) == 1):
return "".join(strs)
ans = ""
minLength = 300
for s in strs:
minLength = min(minLength, len(s))
for i in range(minLength):
c = strs[0][i]
print(c)
for j in range(len(strs)):
if (strs[j][i] != c):
return ans
ans += c
return ans

反转字符串中的单词

给你一个字符串 s ，请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

** 注意：** 输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中，单词间应当仅用单个空格分隔，且不包含任何额外的空格。

示例 1：

Copy
输入：s = "the sky is blue"
输出："blue is sky the"

示例 2：

Copy
输入：s = " hello world "
输出："world hello"
解释：反转后的字符串中不能存在前导空格和尾随空格。

示例 3：

Copy
输入：s = "a good example"
输出："example good a"
解释：如果两个单词间有多余的空格，反转后的字符串需要将单词间的空格减少到仅有一个。

Copy
class Solution:
def reverseWords(self, s: str) -> str:
ans = []
end, start = 0, 0
i = len(s) - 1
while (i >= 0):
if (s[i] == " "):
i -= 1
continue
end = i + 1
while (s[i] != " " and i >= 0):
i -= 1
start = i + 1
ans.append(s[start: end])
return ' '.join(ans)

N 字形变换

将一个给定字符串 s 根据给定的行数 numRows ，以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时，排列如下：

Copy
P A H N
A P L S I I G
Y I R

之后，你的输出需要从左往右逐行读取，产生出一个新的字符串，比如："PAHNAPLSIIGYIR"。

请你实现这个将字符串进行指定行数变换的函数：

Copy
string convert(string s, int numRows);

示例 1：

Copy
输入：s = "PAYPALISHIRING", numRows = 3
输出："PAHNAPLSIIGYIR"

示例 2：

Copy
输入：s = "PAYPALISHIRING", numRows = 4
输出："PINALSIGYAHRPI"
解释：
P I N
A L S I G
Y A H R
P I

示例 3：

Copy
输入：s = "A", numRows = 1
输出："A"

Copy
class Solution:
def convert(self, s: str, numRows: int) -> str:
if (numRows == 1):
return s

res = ["" for _ in range(numRows)]
step = -1
i, j = 0, 0

while (i < len(s)):
if (j == 0 or j == numRows-1):
step = 0 - step
res[j] += s[i]
j += step
i += 1
return ''.join(res)

找出字符串中第一个匹配项的下标

给你两个字符串 haystack 和 needle ，请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标（下标从 0 开始）。如果 needle 不是 haystack 的一部分，则返回 -1 。

示例 1：

Copy
输入：haystack = "sadbutsad", needle = "sad"
输出：0
解释："sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ，所以返回 0 。

示例 2：

Copy
输入：haystack = "leetcode", needle = "leeto"
输出：-1
解释："leeto" 没有在 "leetcode" 中出现，所以返回 -1 。

Copy
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
l1, l2 = len(haystack), len(needle)
if (l2 > l1):
return -1
for i in range(0, l1 - l2 + 1):
if (haystack[i] != needle[0]):
continue
j = 0
while (j < l2 and haystack[i + j] == needle[j]):
j += 1
if (j == l2):
return i
return -1

判断子序列

给定字符串 s 和 t ，判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些（也可以不删除）字符而不改变剩余字符相对位置形成的新字符串。（例如，"ace"是"abcde"的一个子序列，而"aec"不是）。

进阶：

如果有大量输入的 S，称作 S1, S2, ... , Sk 其中 k >= 10 亿，你需要依次检查它们是否为 T 的子序列。在这种情况下，你会怎样改变代码？

示例 1：

Copy
输入：s = "abc", t = "ahbgdc"
输出：true

示例 2：

Copy
输入：s = "axc", t = "ahbgdc"
输出：false

Copy
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
print(s,t)
if(len(s) == 0 or s == t):
return True
for i in range(0,len(t)):
if(t[i] == s[0]):
return self.isSubsequence(s[1:],t[i+1:])
return False

两数之和 II - 输入有序数组

给你一个下标从 1 开始的整数数组 numbers ，该数组已按 非递减顺序排列 ，请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ，则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ，而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例 1：

Copy
输入：numbers = [2,7,11,15], target = 9
输出：[1,2]
解释：2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

示例 2：

Copy
输入：numbers = [2,3,4], target = 6
输出：[1,3]
解释：2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。

示例 3：

Copy
输入：numbers = [-1,0], target = -1
输出：[1,2]
解释：-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

Copy
class Solution:
def twoSum(self, numbers: list[int], target: int) -> list[int]:
start = 0
end = len(numbers) - 1
while(start < end):
if(numbers[start] + numbers[end] == target):
return [start+1,end+1]
elif(numbers[start] + numbers[end] > target):
end -= 1
else:
start += 1

盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线，第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线，使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

** 说明：** 你不能倾斜容器。

示例 1：

Copy
输入：[1,8,6,2,5,4,8,3,7]
输出：49
解释：图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下，容器能够容纳水（表示为蓝色部分）的最大值为 49。

示例 2：

Copy
输入：height = [1,1]
输出：1

Copy
class Solution:
def maxArea(self, height: list[int]) -> int:
start,end = 0,len(height)-1
res = (end-start) * min(height[start],height[end])
while(start < end):
if(height[start] < height[end]):
start += 1
else:
end -= 1
res = max(res,(end-start) * min(height[start],height[end]))
return res