Java基础复习
- Java数组的声明与初始化
- Java ArrayList
- Java HashMap
- Java String 类
- Java LinkedList
- Java Deque继承LinkedList
- Java Set
第一题:有效的括号
很简单的题,从大一做到现在,就是复习一下语法。
class Solution {public boolean isValid(String s) {//先明确一下Java的stack用什么:Deque<Character> stack = new LinkedList<Character>();先进后出为栈//自己可以规定一下用法:addLast, removeLast和getLastint n = s.length();if(n%2!=0){return false;}Deque<Character> stack = new LinkedList<Character>();for(int i=0; i<n; i++){char cur = s.charAt(i);if(cur=='('||cur=='{'||cur=='['){stack.addLast(cur);continue;}if(stack.size()!=0){char top = stack.getLast();if(top=='(' && cur==')'){stack.removeLast();continue;}if(top=='{'&&cur=='}'){stack.removeLast();continue;}if(top=='['&&cur==']'){stack.removeLast();continue;}}return false; }if(stack.size()==0){return true;}else{return false;}}
}
第二题:二叉树的中序遍历
中序遍历顺序:左根右。
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/
class Solution {//怎么改进成用栈呢?这里学习一位大佬的颜色标记法。作者:henrypublic List<Integer> inorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<>();Deque<Object> stack = new LinkedList<>();if(root == null){return res;}stack.push("WHITE");stack.push(root);while(!stack.isEmpty()){TreeNode node = (TreeNode)stack.pop();String color = (String)stack.pop();if (node == null) continue;if(color.equals("WHITE")){stack.push("WHITE");stack.push(node.right);stack.push("GRAY");stack.push(node);stack.push("WHITE");stack.push(node.left);}else{res.add(node.val);}}return res;}//非常简单的回溯法// List<Integer> res = new ArrayList<>();// private void traceBack(TreeNode cur){// if(cur.left != null){// traceBack(cur.left);// }// res.add(cur.val);// if(cur.right != null){// traceBack(cur.right);// }// }// public List<Integer> inorderTraversal(TreeNode root) {// if(root != null){// traceBack(root);// }// return res;// }
}
第三题:移掉k个数字,要求返回最小
维持一个单调栈,单调栈最麻烦的是维持个数。在大佬的题解里面就直接舍弃这个。最后再处理。很有趣。
强推这个大佬的题解!一招吃遍力扣四道题,妈妈再也不用担心我被套路啦~
class Solution {public String removeKdigits(String num, int k) {//特殊情况:k>=num.length()int n = num.length();int remain = n-k;if(remain<=0){return "0";}//定义单调栈Deque<Character> stack = new LinkedList<Character>();//遍历整个num,在其中维护一个长度为无限制的单调栈for(int i=0; i<n; i++){char ch = num.charAt(i);while(!stack.isEmpty()&&k>0&&stack.peekLast()>ch){stack.pollLast();k--;}stack.offerLast(ch);}//只保留栈底的remain个元素for (int i = 0; i < k; ++i) {stack.pollLast();}//处理前导0StringBuilder ret = new StringBuilder();boolean leadingZero = true;while (!stack.isEmpty()) {char digit = stack.pollFirst();if (leadingZero && digit == '0') {continue;}leadingZero = false;ret.append(digit);}return ret.length() == 0 ? "0" : ret.toString();}// int mul[];// int n;// int res=Integer.MAX_VALUE;// int len;// List<Integer> path = new ArrayList<>();// private void traceBack(String num, int idx){// if(idx>n){// return;// }// // System.out.println("path= "+path);// if(path.size()==len){// int tmp=0; // for(int i=0; i<len; i++){// tmp += mul[i] * path.get(i);// }// res = Math.min(tmp, res);// // System.out.println(res + " "+ tmp);// return;// }// for(int i=idx; i<n; i++){// path.add(num.charAt(i)-'0');// traceBack(num, i+1);// path.remove(path.size()-1);// }// }// public String removeKdigits(String num, int k) {// //特殊情况:k>=num.length()// n = num.length();// if(k >= n){// return "0";// }// len = n-k;// mul = new int[n-k];// for(int i=0; i<n-k; i++){// mul[i] = (int) Math.pow((int)10, n-k-i-1);// //System.out.println(mul[i]);// }// //肯定是把k全部用完最好。那就不删除,选择组合?变成组合问题。又想递归回溯了。// //如果是回溯的话,我要画递归树,解空间(i之后的所有)深度(n-k)(不出所料,超时了。)// traceBack(num, 0);// return res+"";// //其实我心里有一个想法,固定栈,里面保证是当前遍历的最小的四个。好像在哪里做过。我需要清醒的脑子过一遍,明天早上来。// //起床了,还是想不到;看了题解:贪心+单调栈// }
}
第四题:去除重复字母,要求返回字典序最小
与上一题基本一致!
class Solution {public String removeDuplicateLetters(String s) {//看过题解过后写的,与402的核心思路是相同的。//前期工作,得到一个map (字母:出现的次数)Map<Character, Integer> container = new HashMap<>();for(int i=0; i<s.length(); i++){if(!container.containsKey(s.charAt(i))){container.put(s.charAt(i), 1);}else{container.put(s.charAt(i), container.get(s.charAt(i))+1);}}//现在出现一个问题,就是前面保留了某个字母之后,后面怎么知道呢?题解里面由加了一个set:当已经保留了,之后的就不在讨论,且数目-1Set<Character> seen = new HashSet<>();int k = container.size();Deque<Character> stack = new LinkedList<>();for(int i=0; i<s.length(); i++){if(!seen.contains(s.charAt(i))){while(!stack.isEmpty()&&container.get(stack.getLast())>1&&stack.getLast()>=s.charAt(i)){container.put(stack.getLast(), container.get(stack.getLast())-1);seen.remove(stack.getLast());stack.removeLast();} stack.addLast(s.charAt(i));seen.add(s.charAt(i));System.out.print(container + " ");System.out.println(stack);}else{container.put(s.charAt(i), container.get(s.charAt(i))-1);}}//只取满足条件的前k个。String res="";while(!stack.isEmpty()&&k>0){res += stack.getFirst()+"";stack.removeFirst();k--;}return res;}
}
第五题:拼接最大数,与前面两题相比,多了一个合并排序。
class Solution {private int[] maxNumberInOne(int[] nums, int k){int res[] = new int[k];int remain = nums.length - k;Deque<Integer> stack = new LinkedList<>();for(int i=0; i<nums.length; i++){while(!stack.isEmpty()&&stack.getLast()<nums[i]&&remain>0){stack.removeLast();remain--;}stack.addLast(nums[i]);}for(int i=0; i<k&&!stack.isEmpty(); i++){res[i] = stack.getFirst();stack.removeFirst();}return res;}//不是简单的归并:查看官方题解,写了一个compare函数比如:public int compare(int[] subsequence1, int index1, int[] subsequence2, int index2) {int x = subsequence1.length, y = subsequence2.length;//按每一位比较while (index1 < x && index2 < y) {int difference = subsequence1[index1] - subsequence2[index2];if (difference != 0) {return difference;}index1++;index2++;}//比较剩余长度 谁的剩余长度大,谁就大return (x - index1) - (y - index2);}private int[] merge(int[] nums1, int[] nums2){int n1 = nums1.length;int n2 = nums2.length;int res[] = new int[n1+n2];Deque<Integer> stack = new LinkedList<>();Arrays.fill(res, 0);int i=0, j=0, k=0;for(; k<n1+n2; k++){if(compare(nums1, i, nums2, j)>0){stack.addLast(nums1[i]);i++;}else{stack.addLast(nums2[j]);j++;}res[k] = stack.getFirst();stack.removeFirst();}return res;}public int[] maxNumber(int[] nums1, int[] nums2, int k) {int res[] = new int[k];Arrays.fill(res, 0);//遍历k1和k2的多种可能(考虑挺多的):1.对于一个数组,最少选多少,最多选多少int n1 = nums1.length;int n2 = nums2.length;int maxk=Math.min(k, n1);int mink;if(n2-k>=0){mink = 0;}else{mink = k-n2; }for(int k1=mink; k1<=maxk; k1++){// System.out.println("min:" + k1 + ", max:" + (k-k1));int res1[] = maxNumberInOne(nums1, k1);int res2[] = maxNumberInOne(nums2, k-k1); // System.out.println("1: "+ Arrays.toString(res1) + "; 2: "+ Arrays.toString(res2));int tmp[] = merge(res1, res2);// System.out.println( Arrays.toString(res));if(compare(res, 0, tmp, 0)<0){res = tmp;}}return res;}
}
根据前两题的大佬的总结,核心就是得到一个单调栈。得到k种可能,每种可能做一个归并,比较。
这个合并排序要重新定义compare函数,因为单纯的选择当前的值做比较,当出现相同数字时,需要根据后续的数字来判断选择哪个数组里的。compare部分参考以下截图理解。