前言
所有题目均来自力扣题库中的hot 100,之所以要记录在这里,只是方便后续复习
20.有效的括号
题目:
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
示例 4:
输入:s = “([)]”
输出:false
示例 5:
输入:s = “{[]}”
输出:true
解题思路:
【栈】这种有一一对应关系且判断是否有效的字符串,可以优先考虑用栈结构。遍历字符串,若当前位置为左括号直接放入栈中即可;若为右括号,判断栈是否为空或者栈顶的值是否和当前右括号为对应关系,为空或非对应关系即无效括号,为对应关系要弹出栈顶的值(代表已经拼成一对);最后看一下是否栈为空,即是否所有左括号都匹配到了右括号,不为空则为无效括号
代码(python):
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
# 判断长度是否为偶数,如果不是偶数则不是有效括号
if len(s) % 2 == 1:
return False
# 初始化栈值,和括号间的对应关系,右括号-左括号(因为只有当时右括号时需要判断对应关系,用右括号当键方便)
stack = list()
values = {
"}": "{",
"]": "[",
")": "("
}
# 遍历字符串
for c in s:
# 当字符是某个右括号时,首先判断栈是否为空,若为空则无效括号;然后看栈顶的值是否和当前右括号是对应关系,若不是则无效括号,若是则弹出栈顶的值
if c in values:
if len(stack) == 0:
return False
last_val = stack.pop()
if last_val != values[c]:
return False
# 当字符串为某个左括号时,则直接放入栈中
else:
stack.append(c)
# 最后看栈是否为空,若为空则代表有效,否则无效括号
if len(stack) == 0:
return True
else:
return False
代码(java):
class Solution {
public boolean isValid(String s) {
if(s.equals("")){
return true;
}
if(s.length() % 2 == 1){
return false;
}
HashMap<Character, Character> map = new HashMap<>();
map.put('{', '}');
map.put('[', ']');
map.put('(', ')');
Stack<Character> stack = new Stack<>();
for(int i = 0; i < s.length(); i++){
if(stack.empty()){
stack.push(s.charAt(i));
}else{
if(map.containsKey(s.charAt(i)) == false && map.containsKey(stack.peek()) && map.get(stack.peek()) == s.charAt(i)){
stack.pop();
}else{
stack.push(s.charAt(i));
}
}
}
if(stack.empty()){
return true;
}else{
return false;
}
}
}
知识点:
- python中可以用list当成栈用,入栈即list.append(),返回栈顶的值即list[-1],弹栈即list.pop()
- python中可以用key in dict 这种方式直接判断字典中是否包含整个键,和has_key()一样
- java中栈的定义就是Stack类,判断为空stack.empty(),入栈stack.push(),出栈stack.pop(),返回栈顶的值stack.peek()
原题链接:有效的括号
394.字符串解码
题目:
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
示例 1:
输入:s = “3[a]2[bc]”
输出:“aaabcbc”
示例 2:
输入:s = “3[a2[c]]”
输出:“accaccacc”
示例 3:
输入:s = “2[abc]3[cd]ef”
输出:“abcabccdcdcdef”
示例 4:
输入:s = “abc3[cd]xyz”
输出:“abccdcdcdxyz”
解题思路:
【栈】这种涉及到左右括号对应关系匹配的可以联想到栈。遍历整个字符串,当前字符是数字时直接入栈即可;当前字符是左括号时直接入栈即可;当前字符是右括号时我们要找出最近的左括号和当前右括号之间的重复内容,然后在找到左括号之前的重复次数,再根据重复次数和重复内容拼成新的字符串,这就完成了这个括号部分的解码,然后再入栈等待后续拼接即可。如何找到重复内容,当遇到右括号时,就循环弹栈直到弹出的值是左括号,将弹出的值倒叙拼接;如何找到重复次数,当找到重复内容后并将左括号弹出后,前面的一定是重复次数,但是重复次数也不一定就是一位,所以也要重复弹栈直到弹出的不是数字或者栈为空,将弹出的值倒叙拼接即重复次数,需要注意的是若是因为弹出的值不是数字而结束弹栈的话要将该值重新入栈;在遍历完成后,再将栈中各个解码后的部分弹出倒叙拼接即整个字符串的解码
代码(python):
from collections import deque
class Solution(object):
def decodeString(self, s):
"""
:type s: str
:rtype: str
"""
stack = deque()
for c in s:
st = str(c)
if st =="]":
new_str = ""
val = stack.pop()
while val != "[":
new_str = val + new_str
val = stack.pop()
new_num = ""
val = stack.pop()
flag = False
while val.isdigit():
new_num = val + new_num
if len(stack) == 0:
flag = True
break
val = stack.pop()
if not flag:
stack.append(val)
new_str = new_str * int(new_num)
stack.append(new_str)
else:
stack.append(st)
result = ""
while len(stack) != 0:
val = stack.pop()
result = val + result
return result
代码(java):
class Solution {
public String decodeString(String s) {
// 初始化栈 注意栈存放的内容是字符串 而不是字符
Stack<String> stack = new Stack<>();
// 遍历字符串
for(int i = 0; i < s.length(); i ++){
//如果当前字符是 ]
if (s.charAt(i) == ']'){
String curStr = "";
// 获取[] 中间的字符串内容:依次弹栈并将取出来的字符串倒序拼接,直到弹出来的是 [
String popVal = stack.pop();
while(popVal.equals("[") == false){
curStr = popVal+ curStr;
popVal = stack.pop();
}
// 获取[]之前的重复次数:依次弹栈并将取出来的字符串倒叙拼接,直至弹出来的不是数字
String repeatStr = "";
popVal = stack.pop();
// 记录一个标记,结束弹栈是因为栈中没值了,还是弹出来的不是数字
boolean flag = true;
while(Character.isDigit(popVal.charAt(0))){
repeatStr = popVal + repeatStr;
// 如果栈中还有值就继续弹栈,没有则将标记取反并跳出弹栈循环
if(stack.size() > 0){
popVal = stack.pop();
}else{
flag = false;
break;
}
}
// 如果标记还是True,说明是因为弹出来的不数字导致中止弹栈操作,要将最后弹出的值放回栈中
if (flag == true){
stack.push(popVal);
}
// 根据拼接出来的重复次数,将[]中间的内容拼接成新的字符串,即该部分字符串解码后,将新字符串放入栈中
String newStr = "";
for(int j = 0; j < Integer.parseInt(repeatStr); j ++){
newStr = newStr + curStr;
}
stack.push(newStr);
// 如果当前字符不是']',是'[' 或数字 直接 入栈即可,注意转化为字符串
}else{
stack.push(Character.toString(s.charAt(i)));
}
}
// 最后将栈中的所有字符串依次弹出并倒叙拼接,即解码后的字符串(栈中存放的是一个一个部分解码字符串,所以注意是所有而不是栈顶)
String result = "";
while(stack.size() > 0){
result = stack.pop() + result;
}
return result;
}
}
知识点:
- python 中可以用deque当栈,弹栈是deque.pop(),入栈是deque.append()
- python 判断字符是否为数字方法:str.isdigit();java中则可以转化为判断字符串中每个字符是否为数字,判断字符是否为数字的方法Character.isDigit()
- python中可以用 str * 10表示将str拼接10次
- java中字符转为字符串的方法Character.toString()
原题链接:字符串解码
155.最小栈
题目:
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
示例 1:
输入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
解题思路:
【栈】定义连个栈,一个用来存放值,一个用来存放当前的最小值;两个栈为一一对应关系,同时入栈同时出栈;当存放最小值的栈为空时直接将值入栈即可,若不为空将栈顶值和当前值对比,较小值入栈即可
代码(python):
class ListNode:
left = None
val = None
def __init__(self, left, val):
self.left = left
self.val = val
class MinStack:
min_val = None
head = None
def __init__(self):
"""
initialize your data structure here.
"""
def push(self, x: int) -> None:
if self.head is None:
self.head = ListNode(None, x)
self.min_val = x
else:
node = ListNode(self.head, x)
self.head = node
self.min_val = min(self.min_val, x)
def pop(self) -> None:
if self.head is not None:
result = self.head.val
self.head = self.head.left
self.min_val = self.__get_min_val()
def top(self) -> int:
if self.head is not None:
return self.head.val
def getMin(self) -> int:
return self.min_val
def __get_min_val(self):
if self.head is None:
return
node = self.head
result = node.val
while node != None:
result = min(result, node.val)
node = node.left
return result
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
代码(java):
class MinStack {
//定义栈:用来存放当前栈中最小值,和存放值的栈一一定义,同时入栈和出栈
private Stack<Integer> minStack = new Stack<>();
//定义栈:用来存放值
private Stack<Integer> myStack = new Stack<>();
public MinStack() {
}
public void push(int val) {
//将值放入存放值的栈
myStack.push(val);
//判断存放最小值的栈中是否为空,若为空将该值直接入栈;若不为空 比较栈顶的值和当前值大小,将较小的值放入栈中,代表该值入栈后最小值是多少
if(minStack.empty()){
minStack.push(val);
}else{
minStack.push(Math.min(minStack.peek(), val));
}
}
public void pop() {
// 存放值的栈 和 存放最小值的栈同时出栈
myStack.pop();
minStack.pop();
}
public int top() {
//返回存放值的栈顶元素即可
return myStack.peek();
}
public int getMin() {
//返回存放最小值的栈顶元素即可
return minStack.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
知识点:
- java中栈也可以用Stack类,同样包含pop,push,empty,peek等操作
原题链接:最小栈
136.只出现一次的数字
题目:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
解题思路:
【位运算】两个相同的数异或都等于0;0和任何数异或都等于任何数;这样我们将数组中的元素都异或一遍,出现两次的数异或的结果都是0,就演变成了若干个0和出现一次的元素异或,结果自然是该数的值
代码(python):
class Solution(object):
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# 初始化异或结果 0
result = 0
# 对应每个数都异或一下
for num in nums:
result = result ^ num
# 最后的结果即出现一次的数
return result
代码(java):
class Solution {
public int singleNumber(int[] nums) {
int single = 0;
for (int i = 0; i < nums.length; i++){
single = single ^ nums[i];
}
return single;
}
}
知识点:
- 两个相同的数异或都等于0
- 0和任何数异或都等于任何数
- python和java中异或符号都是 ^
原题链接:只出现一次的数字
169.多数元素
题目:
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
示例 2:
输入:[2,2,1,1,1,2,2]
输出:2
解题思路:
【投票法】方法一:数组排序后,返回中间位置的数即可;方法二:遍历数组,用键值对将每个值出现的次数计数,返回最大值即可;方法三:类似于选举投票,我们定义一个候选值和当前票数,遍历整个数组:当前票数为0时将候选值替换为当前值,此外若当前值等于候选值则将当前票数+1,否则-1(在更换候选值时,一定和当前值相等,这时也要票数+1,就像自己一定会投自己一票),最终的候选值即结果值
代码(python):
class Solution(object):
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# 定义候选值
val = 0
# 定义票数
count = 0
#遍历数组
for num in nums:
#票数等于0,让候选值等于当前值
if count == 0:
val = num
# 判断当前值与候选值是否相等,若相等则票数+1;不等则-1
if num == val:
count += 1
else:
count -= 1
#返回候选值
return val
代码(java):
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++){
if (map.keySet().contains(nums[i])){
map.put(nums[i], map.get(nums[i]) + 1);
}else{
map.put(nums[i], 1);
}
}
for(Integer key : map.keySet()){
if (map.get(key) > (nums.length)/2){
return key;
}
}
return 0;
}
}
知识点:
- python中向下取整可以用 //
- java中HashMap判断是否包含某个键:map.keySet().contains(key);赋值是map.put(key, value);取值是map.get(key)
原题链接:多数元素