Java基础复习
- Java数组的声明与初始化
- Java ArrayList
- Java HashMap
- Java String 类
- Java LinkedList
- Java Deque继承LinkedList
- Java Set
第一题:有效的括号
很简单的题,从大一做到现在,就是复习一下语法。
java
class Solution {
public boolean isValid(String s) {
//先明确一下Java的stack用什么:Deque<Character> stack = new LinkedList<Character>();先进后出为栈
//自己可以规定一下用法:addLast, removeLast和getLast
int 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;
}
}
}
第二题:二叉树的中序遍历
中序遍历顺序:左根右。
java
/**
* 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 {
//怎么改进成用栈呢?这里学习一位大佬的颜色标记法。作者:henry
public 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个数字,要求返回最小
维持一个单调栈,单调栈最麻烦的是维持个数。在大佬的题解里面就直接舍弃这个。最后再处理。很有趣。
强推这个大佬的题解!一招吃遍力扣四道题,妈妈再也不用担心我被套路啦~
java
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();
}
//处理前导0
StringBuilder 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+"";
// //其实我心里有一个想法,固定栈,里面保证是当前遍历的最小的四个。好像在哪里做过。我需要清醒的脑子过一遍,明天早上来。
// //起床了,还是想不到;看了题解:贪心+单调栈
// }
}
第四题:去除重复字母,要求返回字典序最小
与上一题基本一致!
java
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:当已经保留了,之后的就不在讨论,且数目-1
Set<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;
}
}
第五题:拼接最大数,与前面两题相比,多了一个合并排序。
java
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部分参考以下截图理解。