LeetCode 剑指 Offer 刷题代码 (4)

面试题58 - II. 左旋转字符串

    public String reverseLeftWords(String s, int n) {
        return s.substring(n)+s.substring(0,n);
    }

面试题58 - I. 翻转单词顺序

    public String reverseWords(String s) {
        s = s.trim();
        char[] arr = s.toCharArray();
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] == ' ' && arr[i - 1] == ' ')
                arr[i - 1] = '|';
        }
        String s1 = "", res ="";
        for(char c:arr)
            s1 += c+"";
        
        String[] split = s1.replace("|","").split(" ");
        for(int i=split.length-1; i>=0; i--)
            res += split[i] + " ";
        return res.trim();
    }

面试题57 - II. 和为s的连续正数序列

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

    public int[][] findContinuousSequence(int target) {
        ArrayList<int[]> list = new ArrayList<>();

        int i=1,j=2, sum=1+2;
        while(i<=target/2 && j<=target/2+1){
            if(sum>target){
                sum -= i++;
            }else if(sum<target){
                j++;
                sum += j;
            }else{ //==
                int []arr = new int[j-i+1];
                for(int k=i,q=0; k<=j; k++,q++) arr[q] = k;
                list.add(arr);
                sum += ++j;
            }
        }
        int res[][] = new int[list.size()][];
        for(i=0; i<list.size(); i++)
            res[i] = list.get(i);
        return res;
    }

面试题57. 和为s的两个数字

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

    public int[] twoSum(int[] nums, int target) {
        int i = 0, j = nums.length - 1;
        while (i < j - 1) {
            if (nums[i] + nums[j] < target)
                i++;
            else if (nums[i] + nums[j] > target)
                j--;
            else //==
                break;
        }
        return new int[]{nums[i], nums[j]};
    }

面试题56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

    public int[] singleNumbers(int[] nums) {
        int tmp = 0;
        for (int i = 0; i < nums.length; i++)
            tmp = tmp ^ nums[i];
        int one = tmp & (-tmp);
        
        int res1 = 0, res2 = 0;
        for (int i = 0; i < nums.length; i++)
            if ((nums[i] & one) == one)
                res1 ^= nums[i];
            else
                res2 ^= nums[i];
        return new int[]{res1, res2};
    }

面试题55 - II. 平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

    public boolean isBalanced(TreeNode root) {
        if(root==null)
            return true;
        if(Math.abs(maxDepth(root.left)-maxDepth(root.right))>1)
            return false;
        return isBalanced(root.left) && isBalanced(root.right);
    }

    public int maxDepth(TreeNode root) {
        if(root==null)
            return 0;
        return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
    }

面试题55 - I. 二叉树的深度

    public int maxDepth(TreeNode root) {
        if(root==null)
            return 0;
        return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
    }

面试题54. 二叉搜索树的第k大节点

给定一棵二叉搜索树,请找出其中第k大的节点。

	//非递归中序遍历
    public int kthLargest(TreeNode root, int k) {
        Stack<TreeNode> stack = new Stack<>();
        TreeNode tmp = root;
        int count = 0;
        while(tmp!=null || !stack.empty()){
            while(tmp!=null){
                stack.add(tmp);
                tmp = tmp.right;
            }
            TreeNode node = stack.pop();
            count++;
            if(count==k) return node.val;
            tmp = node.left;
        }
        return -1;
    }

面试题53 - II. 0~n-1中缺失的数字

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

    public int missingNumber(int[] nums) {
        int left=0, right=nums.length-1, mid;
        while(left<=right){
            mid = (left+right)/2;
            if(nums[mid]==mid) left = mid+1;
            else right = mid-1;
        }
        return left;
    }

面试题53 - I. 在排序数组中查找数字 I

统计一个数字在排序数组中出现的次数。

    public int search(int[] nums, int target) {
        int res=0, left = 0, right = nums.length-1, mid=0;
        while(left<=right){
            mid = (left+right)/2;
            if(nums[mid]>target) 
                right = mid-1;
            else if(nums[mid]<target)
                left = mid+1;
            else{
                res++;
                break;
            }
        }
        left = mid-1;
        while(left>=0 && nums[left--]==target) res++;
        right = mid+1;
        while(right<nums.length && nums[right++]==target) res++;
        
        return res;
    }

面试题52. 两个链表的第一个公共节点

    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        Stack<ListNode> stackA = new Stack<>();
        Stack<ListNode> stackB = new Stack<>();
        ListNode tmpA = headA, tmpB = headB, res = null;

        while(tmpA!=null) {
            stackA.push(tmpA);
            tmpA = tmpA.next;
        }
        while(tmpB!=null) {
            stackB.push(tmpB);
            tmpB = tmpB.next;
        }
        if(stackA.empty() || stackB.empty())
            return null;
        while(!stackA.empty() && !stackB.empty() && stackA.peek()==stackB.peek()){
            res = stackA.pop();
            stackB.pop();
        }
        return res;
    }

面试题51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

	private int res = 0;
    public int reversePairs(int[] nums) {
        mergeSort(nums,0,nums.length-1,new int[nums.length]);
        return res;
    }

    private void mergeSort(int[] nums, int s, int e, int[] tmp) {
        if(s>=e)
            return;
        int mid = (s+e)/2;
        mergeSort(nums, s, mid, tmp);
        mergeSort(nums, mid+1, e, tmp);
        merge(nums,s,mid,e,tmp);
    }

    private void merge(int[] nums, int s, int mid, int e, int[] tmp) {
        int i=s,j=mid+1,k=s;
        while(i<=mid && j<=e){
            if(nums[i]<=nums[j])
                tmp[k++] = nums[i++];
            else{
                tmp[k++] = nums[j++];
                res += mid-i+1;
            }
        }
        while(i<=mid)
            tmp[k++] = nums[i++];
            
        while (j<=e)
            tmp[k++] = nums[j++];

        for(i=s; i<=e; i++)
            nums[i] = tmp[i];
    }

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

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。

    public char firstUniqChar(String s) {
        LinkedHashMap<Character, Integer> map = new LinkedHashMap<>();
        for(int i=0; i<s.length(); i++){
            char c = s.charAt(i);
            if(map.containsKey(c))
                map.put(c,map.get(c)+1);
            else
                map.put(c,1);
        }
        for(char c : map.keySet())
            if(map.get(c)==1)
                return c;
        return ' ';
    }

面试题49. 丑数

我们把只包含因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。

    public int nthUglyNumber(int n) {
        int p2=0,p3=0,p5=0,index=0;
        int []arr = new int[n];
        arr[index++] = 1;
        while(index<n){
            int tmp = Math.min(arr[p2]*2,Math.min(arr[p3]*3,arr[p5]*5));
            if(tmp==arr[p2]*2) p2++;
            if(tmp==arr[p3]*3) p3++;
            if(tmp==arr[p5]*5) p5++;
            arr[index++] = tmp;
        }
        return arr[n-1];
    }

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

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

    public int lengthOfLongestSubstring(String s) {
        HashMap<Character, Integer> map = new HashMap<>();
        int max = 0;
        for(int head=0,tail=0; tail<s.length(); tail++){
            if(map.containsKey(s.charAt(tail))){
                head = Math.max(map.get(s.charAt(tail))+1,head);
            }
            map.put(s.charAt(tail),tail);
            max = Math.max(tail-head+1,max);
        }
        return max;
    }

面试题47. 礼物的最大价值

在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

	//动态规划 f(i, j) = max{f(i - 1, j), f(i, j - 1)} + grid[i][j]
    public int maxValue(int[][] grid) {

        for(int i=0; i<grid.length; i++){
            for(int j=0; j<grid[0].length; j++){
                int max = -1;
                if(i==0&&j==0) continue;
                if(i-1>=0) max = grid[i-1][j];
                if(j-1>=0) max = max>grid[i][j-1]?max:grid[i][j-1];
                grid[i][j] += max;
            }
        }
        return grid[grid.length-1][grid[0].length-1];
    }
	//超时
    private int res = 0;
    private int n,m;
    public int maxValue(int[][] grid) {
        if(grid==null || grid.length==0)
            return 0;
        n = grid.length; m=grid[0].length;
        dfs(grid,0,0,0);
        return res;
    }

    private void dfs(int[][] arr, int x, int y, int sum) {
        if(x==n-1 && y==m-1){
            sum += arr[x][y];
            res = res>sum?res:sum;
            return;
        }
        if(x+1<n)
            dfs(arr,x+1,y,sum+arr[x][y]);
        if(y+1<m)
        dfs(arr,x,y+1,sum+arr[x][y]);
    }

面试题46. 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

    public int translateNum(int num) {
        if(num<=9)
            return 1;
        if(num%100<=9 || num%100>=26)
            return translateNum(num/10);
        return translateNum(num/10)+translateNum(num/100);
    }

面试题45. 把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

    public String minNumber(int[] nums) {
        return Arrays.stream(nums).mapToObj(num->num+"")
                .sorted((i,j)->(i+j).compareTo(j+i))
                .collect(Collectors.joining());
    }

面试题44. 数字序列中某一位的数字

数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。

     public int findNthDigit(int n) {
        if(n<10)
            return n;
        long k=1,sum=n,s= (long) (Math.pow(10,k-1)*9);
        while(sum>s){
            sum -= s;
            k++;
            s = (long) (Math.pow(10,k-1)*9)*k;
        }
        String res = (int)(Math.pow(10,k-1)+(sum-1)/k) +"";
        int mod = (int)((sum-1) % k);
        return res.charAt(mod)-'0';
    }

你可能感兴趣的:(LeetCode 剑指 Offer 刷题代码 (4))