【剑指Offer】Java题解汇总(中)

【剑指Offer】Java题解汇总(中)

26. 对称的二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isSym(root,root);
    }
    public boolean isSym(TreeNode rootA, TreeNode rootB){
        if(rootA == null && rootB == null){
            return true;
        }
        if(rootA == null || rootB == null){
            return false;
        }
        if(rootA.val != rootB.val){
            return false;
        }
        return isSym(rootA.left,rootB.right) && isSym(rootA.right,rootB.left);
    }
}

27. 顺时针打印矩阵

class Solution {
    int[] res;
    int index = 0;
    public int[] spiralOrder(int[][] matrix) {
        if(matrix == null || matrix.length <= 0 || matrix[0].length <= 0){
            return new int[]{};
        }
        int start = 0;
        int rows = matrix.length;
        int cols = matrix[0].length;
        res = new int[rows*cols];

        while(rows>start*2 && cols>start*2){
            spiralOrderToInt(matrix,cols,rows,start);
            start ++;
        }
        return res;
    }
    public void spiralOrderToInt(int[][] matrix,int cols,int rows,int start){
        int rowEnd = rows-1-start;
        int colEnd = cols-1-start;
        //1.从左往右打印一行
        for(int i=start; i<=colEnd; i++){
            res[index] = matrix[start][i];
            index ++;
        }
        //2.从上往下
        if(start < rowEnd){
            for(int i=start+1; i<=rowEnd; i++){
                res[index] = matrix[i][colEnd];
                index ++;
            }
        }
        //3.从右往左
        if(start<rowEnd && start<colEnd){
            for(int i=colEnd-1; i>=start; i--){
                res[index] = matrix[rowEnd][i];
                index ++;
            }
        }
        //4.从下往上
        if(start<colEnd && start+1<rowEnd){
            for(int i=rowEnd-1; i>=start+1; i--){
                res[index] = matrix[i][start];
                index ++;
            }
        }
    }
}

28. 包含min函数的栈

class MinStack {
    Stack<Integer> stack;
    Stack<Integer> stackAssit;
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack();
        stackAssit = new Stack();
    }
    
    public void push(int x) {
        stack.push(x);
        if(stackAssit.empty() || stackAssit.peek() > x){
            stackAssit.push(x);
        } else {
            stackAssit.push(stackAssit.peek());
        }
    }
    
    public void pop() {
        if(!stack.empty() && !stackAssit.empty()){
            stack.pop();
            stackAssit.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int min() {
        return stackAssit.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */

29. 栈的压入、弹出序列

参考:https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/solution/mian-shi-ti-31-zhan-de-ya-ru-dan-chu-xu-lie-mo-n-2/

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stack = new Stack<>();
        int i = 0;
        for(int num : pushed) {
            stack.push(num); // num 入栈
            while(!stack.isEmpty() && stack.peek() == popped[i]) { // 循环判断与出栈
                stack.pop();
                i++;
            }
        }
        return stack.isEmpty();
    }
}

30. 从上到下打印二叉树(1)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] levelOrder(TreeNode root) {
        if(root == null){
            return new int[]{};
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        List<Integer> resArr = new ArrayList<Integer>();
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            resArr.add(node.val);
            if(node.left != null){
                queue.offer(node.left);
            }
            if(node.right != null){
                queue.offer(node.right);
            }
        }
        int[] res = new int[resArr.size()];
        for(int i=0; i<resArr.size(); i++){
            res[i] = resArr.get(i);
        }
        return res;
    }
}

31. 从上到下打印二叉树(2)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null){
            List<List<Integer>> list = new ArrayList<>();
            return list;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        List<Integer> listRow = new ArrayList<Integer>();
        List<List<Integer>> list = new ArrayList<>();
        int numNowLine = 1;
        int numAfterLine = 0;
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            listRow.add(node.val);
            numNowLine --;

            if(node.left != null){
                queue.offer(node.left);
                numAfterLine ++;
            }
            if(node.right != null){
                queue.offer(node.right);
                numAfterLine ++;
            }

            if(numNowLine == 0){
                list.add(listRow);
                listRow = new ArrayList<Integer>();
                numNowLine = numAfterLine;
                numAfterLine = 0;
            }
        }
        return list;
    }
}

32. 从上到下打印二叉树(3)之字形

用了两个栈来回的方法

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null){
            List<List<Integer>> list = new ArrayList<>();
            return list;
        }
        Stack<TreeNode> stack1 = new Stack<TreeNode>();
        Stack<TreeNode> stack2 = new Stack<TreeNode>();
        List<List<Integer>> list = new ArrayList<>();
        stack1.push(root);
        //int lines = 1;

        while(!stack1.empty() || !stack2.empty()){
            List<Integer> listRow = new ArrayList<Integer>();
            TreeNode node;
            while(!stack1.empty()){
                node = stack1.pop();
                listRow.add(node.val);
                if(node.left != null){
                    stack2.push(node.left);
                }
                if(node.right != null){
                    stack2.push(node.right);
                }
            }
            if(listRow.size() > 0){
                list.add(listRow);
            }
            listRow = new ArrayList<Integer>();
            while(!stack2.empty()){
                node = stack2.pop();
                listRow.add(node.val);
                if(node.right != null){
                    stack1.push(node.right);
                }
                if(node.left != null){
                    stack1.push(node.left);
                }
            }
            if(listRow.size() > 0){
                list.add(listRow);
            }
        }
        return list;
    }
}

33. 二叉搜索树的后序遍历序列

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return verifySub(postorder, 0, postorder.length-1);
    }
    public boolean verifySub(int[] postorder, int i, int j){
        if(i >= j) return true;
        int p = i;
        while(postorder[p] < postorder[j]) p++;
        int m = p;
        while(postorder[p] > postorder[j]) p++;
        return p == j && verifySub(postorder, i, m - 1) && verifySub(postorder, m, j - 1);

    }
}

34. 二叉树中和为某一值的路径

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 /*
class Solution {
    List<List<Integer>> list = new LinkedList<>();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        if(root == null){
            return list;
        }
        LinkedList<Integer> path = new LinkedList<Integer>();
        int currentSum = 0;
        findPath(root,sum,path,currentSum);
        return list;
        
    }
    public void findPath(TreeNode root, int sum, LinkedList<Integer> path, int currentSum){
        currentSum = currentSum+root.val;
        path.add(root.val);

        boolean isLeaf = root.left==null && root.right==null;
        if(currentSum==sum && isLeaf){
            list.add(path);
            path = new LinkedList<Integer>();
        }
        if(root.left != null){
            findPath(root.left,sum,path,currentSum);
        }
        if(root.right != null){
            findPath(root.right,sum,path,currentSum);
        }
        path.removeLast();
    }
}*/

class Solution {
    LinkedList<List<Integer>> res = new LinkedList<>();
    LinkedList<Integer> path = new LinkedList<>(); 
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        recur(root, sum);
        return res;
    }
    void recur(TreeNode root, int tar) {
        if(root == null) return;
        path.add(root.val);
        tar -= root.val;
        if(tar == 0 && root.left == null && root.right == null)
            res.add(new LinkedList(path));
        recur(root.left, tar);
        recur(root.right, tar);
        path.removeLast();
    }
}

35. 复杂链表的复制

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        if(head==null){
            return null;
        }
        copy(head);
        randomDirect(head);
        return reList(head);
    }
    //拷贝链表
    private void copy(Node head){
        while(head!=null){
            Node cloneNode = new Node(head.val);
            Node nextNode = head.next;
            head.next = cloneNode;
            cloneNode.next = nextNode;
            head = cloneNode.next;
        }
    }
    //指定随机指针
    private void randomDirect(Node head){
        while(head!=null){
            Node cloneNode = head.next;
            if(head.random!=null){
                Node direct = head.random;
                cloneNode.random = direct.next;
            }
            head = cloneNode.next;
        }
    }
    //重新连接 链表
    private Node reList(Node head){
        Node cloneNode = head.next;
        Node cloneHead = cloneNode;
        head.next = cloneNode.next;
        head = head.next;
        while(head!=null){
            cloneNode.next = head.next;
            head.next = head.next.next;
            head = head.next;
            cloneNode = cloneNode.next;
        }
        return cloneHead;
    }
}

36. 二叉搜索树与双向链表

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
    Node head, pre;
    public Node treeToDoublyList(Node root) {
        if(root==null) return null;
        dfs(root);

        pre.right = head;
        head.left =pre;//进行头节点和尾节点的相互指向,这两句的顺序也是可以颠倒的

        return head;

    }

    public void dfs(Node cur){
        if(cur==null) return;
        dfs(cur.left);

        //pre用于记录双向链表中位于cur左侧的节点,即上一次迭代中的cur,当pre==null时,cur左侧没有节点,即此时cur为双向链表中的头节点
        if(pre==null) head = cur;
        //反之,pre!=null时,cur左侧存在节点pre,需要进行pre.right=cur的操作。
        else pre.right = cur;
       
        cur.left = pre;//pre是否为null对这句没有影响,且这句放在上面两句if else之前也是可以的。

        pre = cur;//pre指向当前的cur
        dfs(cur.right);//全部迭代完成后,pre指向双向链表中的尾节点
    }
}

37. 序列化/反序列化二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {
    public String serialize(TreeNode root) {
        if(root == null) return "[]";
        StringBuilder res = new StringBuilder("[");
        Queue<TreeNode> queue = new LinkedList<>() {{ add(root); }};
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(node != null) {
                res.append(node.val + ",");
                queue.add(node.left);
                queue.add(node.right);
            }
            else res.append("null,");
        }
        res.deleteCharAt(res.length() - 1);
        res.append("]");
        return res.toString();
    }

    public TreeNode deserialize(String data) {
        if(data.equals("[]")) return null;
        String[] vals = data.substring(1, data.length() - 1).split(",");
        TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
        Queue<TreeNode> queue = new LinkedList<>() {{ add(root); }};
        int i = 1;
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(!vals[i].equals("null")) {
                node.left = new TreeNode(Integer.parseInt(vals[i]));
                queue.add(node.left);
            }
            i++;
            if(!vals[i].equals("null")) {
                node.right = new TreeNode(Integer.parseInt(vals[i]));
                queue.add(node.right);
            }
            i++;
        }
        return root;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

38. 字符串的排列

class Solution {
    //为了让递归函数添加结果方便,定义到函数之外,这样无需带到递归函数的参数列表中
    List<String> list = new ArrayList<>();
    //同;但是其赋值依赖c,定义声明分开
    char[] c;
    public String[] permutation(String s) {
        c = s.toCharArray();
        //从第一层开始递归
        dfs(0);
        //将字符串数组ArrayList转化为String类型数组
        return list.toArray(new String[list.size()]);
    }

    private void dfs(int x) {
        //当递归函数到达第三层,就返回,因为此时第二第三个位置已经发生了交换
        if (x == c.length - 1) {
            //将字符数组转换为字符串
            list.add(String.valueOf(c));
            return;
        }
        //为了防止同一层递归出现重复元素
        HashSet<Character> set = new HashSet<>();
        //这里就很巧妙了,第一层可以是a,b,c那么就有三种情况,这里i = x,正巧dfs(0),正好i = 0开始
        // 当第二层只有两种情况,dfs(1)i = 1开始
        for (int i = x; i < c.length; i++){
            //发生剪枝,当包含这个元素的时候,直接跳过
            if (set.contains(c[i])){
                continue;
            }
            set.add(c[i]);
            //交换元素,这里很是巧妙,当在第二层dfs(1),x = 1,那么i = 1或者 2, 不是交换1和1,要就是交换1和2
            swap(i,x);
            //进入下一层递归
            dfs(x + 1);
            //返回时交换回来,这样保证到达第1层的时候,一直都是abc。这里捋顺一下,开始一直都是abc,那么第一位置总共就3个交换
            //分别是a与a交换,这个就相当于 x = 0, i = 0;
            //     a与b交换            x = 0, i = 1;
            //     a与c交换            x = 0, i = 2;
            //就相当于上图中开始的三条路径
            //第一个元素固定后,每个引出两条路径,
            //     b与b交换            x = 1, i = 1;
            //     b与c交换            x = 1, i = 2;
            //所以,结合上图,在每条路径上标注上i的值,就会非常容易好理解了
            swap(i,x);
        }
    }

    private void swap(int i, int x) {
        char temp = c[i];
        c[i] = c[x];
        c[x] = temp;
    }
}

39. 数组中出现次数超过一半的数字

class Solution {
    public int majorityElement(int[] nums) {
        int cnt = 1;
        int element = nums[0];
        for(int i=1; i<nums.length; i++){
            if(cnt == 0){
                element = nums[i];
                cnt = 1;
            }
            else if(nums[i] == element){
                cnt ++;
            } else {
                cnt --;
            }
        }
        //还可以验证一下这个是不是大于一半多的数字

        return element;
    }
}

40. 最小的k个数

class Solution {
    /*
    //用快速选择排序来实现
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] res = new int[k];
        if(arr.length <= k){
            return arr;
        }
        if(k == 0){
            return res;
        }
        for(int i=0; i<k; i++){
            int minIndex = i;
            int min = arr[i];
            for(int j=i+1; j<arr.length; j++){
                if(min > arr[j]){
                    min = arr[j];
                    minIndex = j;
                }
                
            }
            if(minIndex != i){
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
        }
        
        for(int i=0; i<k; i++){
            res[i] = arr[i];
        }
        return res;
    }
    */
    //用一个队列来维护
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] vec = new int[k];
        if (k == 0) { // 排除 0 的情况
            return vec;
        }
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() {
            public int compare(Integer num1, Integer num2) {
                return num2 - num1;
            }
        });
        for (int i = 0; i < k; ++i) {
            queue.offer(arr[i]);
        }
        for (int i = k; i < arr.length; ++i) {
            if (queue.peek() > arr[i]) {
                queue.poll();
                queue.offer(arr[i]);
            }
        }
        for (int i = 0; i < k; ++i) {
            vec[i] = queue.poll();
        }
        return vec;
    }

}

41. 数据流中的中位数

参考:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof/solution/mian-shi-ti-41-shu-ju-liu-zhong-de-zhong-wei-shu-y/

class MedianFinder {
    Queue<Integer> A, B;
    public MedianFinder() {
        A = new PriorityQueue<>(); // 小顶堆,保存较大的一半
        B = new PriorityQueue<>((x, y) -> (y - x)); // 大顶堆,保存较小的一半
    }
    public void addNum(int num) {
        if(A.size() != B.size()) {
            A.add(num);
            B.add(A.poll());
        } else {
            B.add(num);
            A.add(B.poll());
        }
    }
    public double findMedian() {
        return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;
    }
}


/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

42. 连续子数组的最大和

动态规划

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        for(int i=1; i<nums.length; i++){
            if(nums[i-1] > 0){
                nums[i] = nums[i-1] +nums[i];
            }
            if(res < nums[i]){
                res = nums[i];
            }
        }
        return res;
    }
}

43. 1-n整数中1出现的次数

参考讲解:https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/mian-shi-ti-43-1n-zheng-shu-zhong-1-chu-xian-de-2/

class Solution {
    public int countDigitOne(int n) {
        int res = 0;
        int cur = n%10;
        int high = n/10;
        int low = 0;
        int digit = 1;

        while(high!=0 || low!=n){
            if(cur == 0){
                res += high*digit;
            } else if(cur == 1){
                res += high*digit + low + 1;
            } else{
                res += (high+1)*digit;
            }
            low += cur*digit;
            cur = high%10;
            high = high/10;
            digit *= 10;

        }
        return res;
    }
}

44. 数字序列中某一位的数字

class Solution {
    public int findNthDigit(int n) {
        if(n == 0){
            return 0;
        }
        int digit = 1;
        long start = 1;
        long count = 9;
        while(n > count){
            n -= count;
            digit ++;
            start *= 10;
            count = 9*start*digit;
        }
        long num = start+(n-1)/digit;
        return Long.toString(num).charAt((n-1)%digit)-'0';
    }
}

45. 把数组排成最小的数

/*
class Solution {
    public String minNumber(int[] nums) {
        String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++)
            strs[i] = String.valueOf(nums[i]);
        fastSort(strs, 0, strs.length - 1);
        StringBuilder res = new StringBuilder();
        for(String s : strs)
            res.append(s);
        return res.toString();
    }
    void fastSort(String[] strs, int l, int r) {
        if(l >= r) return;
        int i = l, j = r;
        String tmp = strs[i];
        while(i < j) {
            while((strs[j] + strs[l]).compareTo(strs[l] + strs[j]) >= 0 && i < j) j--;
            while((strs[i] + strs[l]).compareTo(strs[l] + strs[i]) <= 0 && i < j) i++;
            tmp = strs[i];
            strs[i] = strs[j];
            strs[j] = tmp;
        }
        strs[i] = strs[l];
        strs[l] = tmp;
        fastSort(strs, l, i - 1);
        fastSort(strs, i + 1, r);
    }
}
*/

class Solution {
    public String minNumber(int[] nums) {
        String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++) 
            strs[i] = String.valueOf(nums[i]);
        Arrays.sort(strs, (x, y) -> (x + y).compareTo(y + x));
        StringBuilder res = new StringBuilder();
        for(String s : strs)
            res.append(s);
        return res.toString();
    }
}

46. 把数字翻译成字符串

class Solution {
    public int translateNum(int num) {
        String s = String.valueOf(num);
        int dp0 = 1;
        int dp1 = 1;
        int res = 0;
        for(int i=2; i<=s.length(); i++){
            String tmp = s.substring(i-2,i);
            if(tmp.compareTo("10")>=0 && tmp.compareTo("25")<=0){
                res = dp0 + dp1;
            } else{
                res = dp1;
            }
            dp0 = dp1;
            dp1 = res;
        }
        return dp1;
    }
}

47. 礼物的最大价值

class Solution {
    public int maxValue(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                int up = 0;
                int left = 0;
                if(i > 0){
                    up = dp[i-1][j];
                }
                if(j > 0){
                    left = dp[i][j-1];
                }
                dp[i][j] = Math.max(up,left) + grid[i][j];
            }
        }
        return dp[m-1][n-1];
    }
}

48. 最长不含重复字符的子字符串

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++) {
            int i = dic.getOrDefault(s.charAt(j), -1); // 获取索引 i
            dic.put(s.charAt(j), j); // 更新哈希表
            tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
            res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
        }
        return res;
    }
}

49. 丑数

class Solution {
    public int nthUglyNumber(int n) {
        int[] dp = new int[n];
        dp[0] = 1;
        int a = 0, b = 0, c = 0;
        for(int i=1; i<n; i++){
            int n2=dp[a]*2, n3=dp[b]*3, n5=dp[c]*5;
            dp[i] = Math.min(Math.min(n2,n3),n5);
            while(dp[a]*2 <= dp[i]){
                a++;
            }
            while(dp[b]*3 <= dp[i]){
                b++;
            }
            while(dp[c]*5 <= dp[i]){
                c++;
            }
        }
        return dp[n-1];
    }
}

50. 第一个只出现一次的字符

/*写法一
class Solution {
    public char firstUniqChar(String s) {
        if(s.length() == 0 || s == null){
            return ' ';
        }
        char[] arrays = s.toCharArray();
        Map<Character,Boolean> map = new HashMap<>();
        for(char array: arrays){
            if(map.containsKey(array)){
                map.put(array,false);
            } else {
                map.put(array,true);
            }
        }
        for(char array: arrays){
            if(map.get(array)){
                return array;
            }
        }
        return ' ';
    }
}
*/
class Solution {
    public char firstUniqChar(String s) {
        HashMap<Character, Boolean> dic = new HashMap<>();
        char[] sc = s.toCharArray();
        for(char c : sc)
            dic.put(c, !dic.containsKey(c));
        for(char c : sc)
            if(dic.get(c)) return c;
        return ' ';
    }
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×