dfs
22.括号的生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]
示例 2:
输入:n = 1
输出:[“()”]
提示:
1 <= n <= 8
思路:
所以的符合条件的组合其实就是一个二叉树,我们遍历这个树就可以得到结果,所以用dfs做:
dfs过程中:
- 符合条件:index==2*n即遍历的括号数为需要的括号数
- 不符合条件,直接return:
2.1 右括号数量大于左括号数量
2.2 左括号数量大于n
public List<String> generateParenthesis(int n) {
List<String> res = new ArrayList<>();
dfs(0,n,0,0,"",res);
return res;
}
private void dfs(int index, int n, int left,int right, String str, List<String> res){
// 不符合条件:1:左边括号数量<右边括号数量 2:左边括号数量大于n
if (left>n||right>left){
return ;
}
// 符合条件:当前的个数等于括号总量
if (index==2*n){
res.add(str);
return ;
}
// 搜索左边
dfs(index+1,n,left+1,right,str+"(",res);
// 搜索右边
dfs(index+1,n,left,right+1,str+")",res);
}
动态规划
22.括号的生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
关键:
dp[i]的定义:表示第i对所有合法的括号列表,所以返回的结果就是dp[n]
初始:dp[0]:[“”] dp[1]:[“()”]
表达式:“(”+dp[p]中任意一个+“)”+dp[q]中任意一个,其中:0=<p<=i-1 p+q = i-1 也就是从前面满足条件的进行任意组合
public List<String> generateParenthesis(int n) {
//dp[i] 表示第i对所有合法的括号列表
List<List<String>> dp = new ArrayList<>();
List<String> dp0 = new ArrayList<>();
dp0.add("");
List<String> dp1 = new ArrayList<>();
dp1.add("()");
dp.add(dp0);
dp.add(dp1);
if (n==1){
return dp.get(1);
}
// dp[i] : "("+dp[p]中任意一个+")"+dp[q]中任意一个
// 其中:0=<p<=i-1 p+q = i-1 也就是从前面满足条件的进行任意组合
for(int i=2;i<=n;i++){
List<String> cur = new ArrayList<>();
// 找到当前i每一个符合条件结果
for (int p=0;p<=i-1;p++){
for (String k : dp.get(p)){
for (String l : dp.get(i-1-p)){
cur.add("("+k+")"+l);
}
}
}
dp.add(cur);
}
return dp.get(n);
}
栈
栈的常用:
// new一个栈
Stack<Character> stack = new Stack<Character>();
// 入栈
stack.push(x);
// 出栈
Character x = stack.pop();
// 判断栈是否为空
stack.isEmpty();
20.有效的括号
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
提示:
1 <= s.length <= 10⁴
s 仅由括号 ‘()[]{}’ 组成
思路:
比较简单,因为左括号必须以正确的顺序闭合,所以只要判断当前右括号是否和栈顶左括号是否匹配就可以了
public boolean isValid(String s) {
if (s.length()%2!=0){
return false;
}
Stack<Character> stack = new Stack<>();
for (int i=0;i<s.length();i++){
if (s.charAt(i)=='(' || s.charAt(i)=='[' || s.charAt(i)=='{'){
stack.push(s.charAt(i));
}else{
if (stack.isEmpty()){
return false;
}
char l = stack.pop();
if (!isMatch(l, s.charAt(i))){
return false;
}
}
}
return stack.isEmpty();
}
public boolean isMatch(char l, char r){
if (l=='(' && r==')'){
return true;
}else if(l=='[' && r==']'){
return true;
}else if(l=='{' && r=='}'){
return true;
}
return false;
}
65. 有效数字
思路:
class Solution {
public boolean isNumber(String s) {
int n = s.length();
char[] cs = s.toCharArray();
int idx = -1;
// 通过 e/E 对字符串进行分割
for (int i = 0; i < n; i++) {
if (cs[i] == 'e' || cs[i] == 'E') {
if (idx == -1) idx = i;
else return false;
}
}
boolean ans = true;
if (idx != -1) {
// e/E 左侧为整数或浮点数
ans &= check(cs, 0, idx - 1, false);
// e/E 右侧必须为整数
ans &= check(cs, idx + 1, n - 1, true);
} else {
ans &= check(cs, 0, n - 1, false);
}
return ans;
}
boolean check(char[] cs, int start, int end, boolean mustInteger) {
if (start > end) return false;
if (cs[start] == '+' || cs[start] == '-') start++;
boolean hasDot = false, hasNum = false;
for (int i = start; i <= end; i++) {
if (cs[i] == '.') {
if (mustInteger || hasDot) return false;
hasDot = true;
} else if (cs[i] >= '0' && cs[i] <= '9') {
hasNum = true;
} else {
return false;
}
}
return hasNum;
}
}
字符串相加
415. 字符串相加
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
提示:
num1 和num2 的长度都小于 5100
num1 和num2 都只包含数字 0-9
num1 和num2 都不包含任何前导零
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式
十进制字符串相加
class Solution {
public String addStrings(String num1, String num2) {
int carry = 0;
int i = num1.length()-1;
int j = num2.length()-1;
String res = "";
while(i>=0 || j>=0 || carry>0){
int x = i>=0?num1.charAt(i)-'0':0;
int y = j>=0?num2.charAt(j)-'0':0;
int temp = x+y+carry;
res+=temp%10;
carry = temp/10;
i--;
j--;
}
return new StringBuilder(res).reverse().toString();
}
}
36进制加法
36进制由0-9,a-z,共36个字符表示。
要求按照加法规则计算出任意两个36进制正整数的和,如1b + 2x = 48 (解释:47+105=152)
要求:不允许使用先将36进制数字整体转为10进制,相加后再转回为36进制的做法
class Solution {
public String add36Strings(String num1, String num2) {
int carry = 0;
int i = num1.length()-1;
int j = num2.length()-1;
String res = "";
while(i>=0 || j>=0 || carry>0){
int x = i>=0?getInt(num1.charAt(i)):0;
int y = j>=0?getInt(num2.charAt(j)):0;
int temp = x+y+carry;
res+=getChar(temp%36);
carry = temp/36;
i--;
j--;
}
return new StringBuilder(res).reverse().toString();
}
public int getInt(char c){
if(c>='0' && c<='9'){
return c-'0';
}else{
return c-'a'+10;
}
}
public char getChar(int x){
if(x<=9){
return x+'0';
}else{
return x-10+'a';
}
}
}
回文系列
647.回文子串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:“abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”
示例 2:
输入:“aaa”
输出:6
解释:6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”
思路: 可以用中心拓展(以每个点作为回文的中心点)的办法,中心拓展的关键就是在于中心可以是一个字符也可以是两个字符
class Solution {
public int countSubstrings(String s) {
int num = 0;
int n = s.length();
// 遍历回文中心点
for (int i = 0; i < n; i++) {
// j==0 表示中心是一个点,j==1 表示中心是两个点
for (int j = 0; j <= 1; j++) {
// 往外拓展看是否为回文
int l = i;
int r = i+j;
while(l>=0 && r<n && s.charAt(l)==s.charAt(r)){
l--;
r++;
num++;
}
}
}
return num;
}
}
表达式
满足加减乘除和括号
- 转成前缀表达式
- 通过前缀表达式进行计算
public class Solution {
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.solve("(1+2)*3+6/2"));
}
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 返回表达式的值
* @param s string字符串 待计算的表达式
* @return int整型
*/
public int solve (String s) {
// write code here
// 得到前缀表达式
ArrayList<String> list = getSuffix(s);
Deque<Integer> stack = new LinkedList<>();
for(String str : list){
if("+".equals(str) || "-".equals(str) || "*".equals(str) || "/".equals(str)){
int a = Integer.valueOf(stack.pop());
int b = Integer.valueOf(stack.pop());
if("+".equals(str)){
stack.push(a + b);
}else if("-".equals(str)){
stack.push(b - a);
}else if("*".equals(str)){
stack.push(a * b);
}else if("/".equals(str)){
stack.push(b/a);
}
}else{
stack.push(Integer.valueOf(str));
}
}
return stack.pop();
}
public ArrayList<String> getSuffix(String s){
HashMap<Character, Integer> map = new HashMap<>();
map.put('+', 0);
map.put('-', 0);
map.put('*', 1);
map.put('/', 1);
int n = s.length();
Deque<Character> stack = new LinkedList<>();
ArrayList<String> list = new ArrayList<>();
int i = 0;
while(i < n){
int index = i;
Character cur = s.charAt(i);
if(cur == '('){
stack.push(cur);
}else if(cur == ')'){
while(!stack.isEmpty() ){
Character ch = stack.pop();
if(ch == '(') break;
list.add(ch.toString());
}
}else if(cur == '+' || cur == '-' || cur == '*'|| cur == '/'){
if (stack.isEmpty()){
stack.push(s.charAt(i));
}else {
while (!stack.isEmpty() &&(stack.peek() == '+' || stack.peek() == '-' || stack.peek() =='*'|| stack.peek() =='/')&&map.get(s.charAt(i)) <= map.get(stack.peek())){
Character pop = stack.pop();
list.add(pop.toString());
}
stack.push(s.charAt(i));
}
}else{
StringBuilder sb = new StringBuilder();
while(i < n && s.charAt(i) >= '0' && s.charAt(i) <= '9'){
sb.append(s.charAt(i));
i++;
}
list.add(sb.toString());
}
if(i == index){
i++;
}
}
while(!stack.isEmpty()){
list.add(stack.pop().toString());
}
return list;
}
}
只有加减括号
class Solution {
public int calculate(String s) {
char[] chars=s.toCharArray();
Stack<Integer>stack=new Stack<>();
int res=0,cur=0,flag=1;
for(int i=0;i<chars.length;i++){
char c=chars[i];
if(c==' ')continue;
if(Character.isDigit(c)){
cur=cur*10+c-'0';
if(i+1<chars.length&&Character.isDigit(chars[i+1])){
continue;
}
}else if(c=='+'||c=='-'){
cur=0;
if(c=='+'){flag=1;}
else flag=-1;
}else if(c=='('){
stack.push(res);
stack.push(flag);
res=0;
flag=1;
}else if(c==')'){
flag=stack.pop();
cur=res;
res=stack.pop();
}
res+=cur*flag;
}
return res;
}
}
加减乘除没括号
class Solution {
public int calculate(String s) {
char[] chars=s.toCharArray();
Stack<Integer>stack=new Stack<>();
int num=0;
char flag='+';
for(int i=0;i<s.length();i++){
char c=chars[i];
if(Character.isDigit(c)){
num=num*10+c-'0';
}if(c<'0'&& c!=' '||i==s.length()-1){
if(flag=='-'){
stack.push(-num);
}
if(flag=='+'){
stack.push(num);
}
if(flag=='*'){
stack.push(stack.pop()*num);
}
if(flag=='/'){
stack.push(stack.pop()/num);
}
flag=c;
num=0;
}
}
int res=0;
while(!stack.isEmpty()){
res+=stack.pop();
}
return res;
}
}