《Java练习题》进阶练习题(五)

编程合集: https://www.cnblogs.com/jssj/p/12002760.html

前言:不仅仅要实现,更要提升性能,精益求精,用尽量少的时间复杂度和空间复杂度解决问题。

【程序88】
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。

/**
 * 给定一个未排序的整数数组,找出其中没有出现的最小的正整数。
 */
public class Subject88 {
    public static void main(String[] args) {
        int[] arrInt = new int[]{-1,-9,1,2,4,6,9,8};
        int number = new Subject88().firstMissingPositive(arrInt);
        System.out.println(number);
    }

    public int firstMissingPositive(int[] nums) {
        int n = nums.length;

        // 基本情况
        int contains = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] == 1) {
                contains++;
                break;
            }
        }
        if (contains == 0)
            return 1;

        // nums = [1]
        if (n == 1)
            return 2;

        // 用 1 替换负数,0,
        // 和大于 n 的数
        // 在转换以后,nums 只会包含
        // 正数
        for (int i = 0; i < n; i++)
            if ((nums[i] <= 0) || (nums[i] > n))
                nums[i] = 1;

        // 使用索引和数字符号作为检查器
        // 例如,如果 nums[1] 是负数表示在数组中出现了数字 `1`
        // 如果 nums[2] 是正数 表示数字 2 没有出现
        for (int i = 0; i < n; i++) {
            int a = Math.abs(nums[i]);
            // 如果发现了一个数字 a - 改变第 a 个元素的符号
            // 注意重复元素只需操作一次
            if (a == n)
                nums[0] = - Math.abs(nums[0]);
            else
                nums[a] = - Math.abs(nums[a]);
        }

        // 现在第一个正数的下标
        // 就是第一个缺失的数
        for (int i = 1; i < n; i++) {
            if (nums[i] > 0)
                return i;
        }

        if (nums[0] > 0)
            return n;

        return n + 1;
    }
}

时间复杂度为 O(n)。

运行结果:

【程序89】
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。感谢 Marcos 贡献此图。

/**
 * 【程序89】
 * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
 * 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。感谢 Marcos 贡献此图。
 */
public class Subject89 {

    public static void main(String[] args) {
        int[] arrInt = new int[]{0,1,4,2,1,0,1,7,2,1,2,6};
        int side = new Subject89().trap(arrInt);
        System.out.println(side);
    }

    public int trap(int[] height) {
        int max = 0;
        int side =0;
        for (int i = 0; i < height.length ; i++) {
            if(height[i] > max){
                max = height[i];
                side = i;
            }
        }

        int unit = 0;
        //右边接收雨水量
        unit = unit + trapRight(height,side);
        //左边接受雨水量
        unit = unit + trapLeft(height,side);
        return unit;
    }

    public int trapRight(int[] height,int side) {
        int unit = 0;
        int maxTmp = 0;
        int sideTmp =0;
        for (int i = height.length-1 ; i >  side; i--) {
            if(height[i] > maxTmp){
                maxTmp = height[i];
                sideTmp = i;
            }
        }

        //计算中间存在多少单位
        unit = trapUnit(height,side,sideTmp);
        if(maxTmp > 0 && sideTmp != height.length-1){
            unit += trapRight(height,sideTmp);
        }
        return unit;
    }

    public int trapLeft(int[] height,int side) {
        int unit = 0;
        int maxTmp = 0;
        int sideTmp =0;
        for (int i = 0 ; i < side; i++) {
            if(height[i] > maxTmp){
                maxTmp = height[i];
                sideTmp = i;
            }
        }
        //计算中间存在多少单位
        unit = trapUnit(height, sideTmp,side);
        if(maxTmp > 0 && sideTmp != 0) {
            unit += trapLeft(height, sideTmp);
        }
        return unit;
    }

    /**
     * 计算中间可以存在多少单位雨水
     * @param height
     * @return
     */
    public int trapUnit(int[] height,int left,int right){
        int unit = 0;
        if(right-left <= 1){
            return unit;
        }

        int low =0;
        if(height[left] > height[right]){
            low = height[right];
        }else{
            low = height[left];
        }

        for (int i = left+1; i <= right-1; i++) {
            unit = unit + (low - height[i]);
        }
        return unit;
    }
}

时间复杂度为 O(n)。

运行结果:

【程序90】
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

/**
 * 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
 */
public class Subject90 {
    public static void main(String[] args) {
        String num1 = "123";
        String num2 = "456";
        String nultiply = new Subject90().multiply(num1,num2);
        System.out.println(nultiply);
    }
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        int[] res = new int[num1.length() + num2.length()];
        for (int i = num1.length() - 1; i >= 0; i--) {
            int n1 = num1.charAt(i) - '0';
            for (int j = num2.length() - 1; j >= 0; j--) {
                int n2 = num2.charAt(j) - '0';
                int sum = (res[i + j + 1] + n1 * n2);
                res[i + j + 1] = sum % 10;
                res[i + j] += sum / 10;
            }
        }

        StringBuilder result = new StringBuilder();
        for (int i = 0; i < res.length; i++) {
            if (i == 0 && res[i] == 0) continue;
            result.append(res[i]);
        }
        return result.toString();
    }
}

时间复杂度为 O(MN)。

运行结果:

【程序91】
给定一个字符串(s) 和一个字符模式(p) ,实现一个支持'?'和'*'的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。

/**
 * 给定一个字符串(s) 和一个字符模式(p) ,实现一个支持'?'和'*'的通配符匹配。
 * '?' 可以匹配任何单个字符。
 * '*' 可以匹配任意字符串(包括空字符串)。
 * 两个字符串完全匹配才算匹配成功。
 */
public class Subject91 {
    public static void main(String[] args) {
        String str1 = "abbabaaabababbaababbabbbbbabbbabb";
        String str2 = "**aa*abb***";
        System.out.println(new Subject91().isMatch(str1,str2));
    }

    boolean isMatch(String str, String pattern) {

        int s = 0, p = 0, match = 0, starIdx = -1;
        //遍历整个字符串
        while (s < str.length()){
            // 一对一匹配,两指针同时后移。
            if (p < pattern.length()  && (pattern.charAt(p) == '?' || str.charAt(s) == pattern.charAt(p))){
                s++;
                p++;
            }
            // 碰到 *,假设它匹配空串,并且用 startIdx 记录 * 的位置,记录当前字符串的位置,p 后移
            else if (p < pattern.length() && pattern.charAt(p) == '*'){
                starIdx = p;
                match = s;
                p++;
            }
            // 当前字符不匹配,并且也没有 *,回退
            // p 回到 * 的下一个位置
            // match 更新到下一个位置
            // s 回到更新后的 match
            // 这步代表用 * 匹配了一个字符
            else if (starIdx != -1){
                p = starIdx + 1;
                match++;
                s = match;
            }
            //字符不匹配,也没有 *,返回 false
            else return false;
        }

        //将末尾多余的 * 直接匹配空串 例如 text = ab, pattern = a*******
        while (p < pattern.length() && pattern.charAt(p) == '*')
            p++;

        return p == pattern.length();
    }
}

时间复杂度为 O(TP)。

运行结果:

【程序92】
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。

/**
 * 给定一个非负整数数组,你最初位于数组的第一个位置。
 * 数组中的每个元素代表你在该位置可以跳跃的最大长度。
 * 你的目标是使用最少的跳跃次数到达数组的最后一个位置。
 */
public class Subject92 {

    public static void main(String[] args) {
        int[] arrInt = new int[]{2,3,1,1,4,2,1};
        System.out.println(new Subject92().jump(arrInt));
    }

    public int jump(int[] nums) {
        //小于等于1的都不需要跳
        int lengths = nums.length;
        if(lengths <= 1){
            return 0;
        }
        int reach = 0;  //当前能走的最远距离
        int nextreach = nums[0];
        int step = 0;  //需要步数
        for(int i = 0;i){
            //贪心算法核心:这一步是不是可以比上一步得到更多步数,可以则取最新的路线。
            nextreach = Math.max(i+nums[i],nextreach);
            if(nextreach >= lengths-1) return (step+1);
            if(i == reach){
                step++;
                reach = nextreach;
            }
        }
        return step;
    }
}

时间复杂度为 O(n)。

运行结果:

【程序93】
给定一个没有重复数字的序列,返回其所有可能的全排列。

import java.util.ArrayList;
import java.util.List;

/**
 * 给定一个没有重复数字的序列,返回其所有可能的全排列。
 */
public class Subject93 {
    public static void main(String[] args) {
        int[] arrInt = new int[]{1,2,3};
        List> integerList1 = new Subject93().permute(arrInt);
        System.out.println(integerList1);
    }

    List> integerList = new ArrayList<>();
    List integerListTmp = new ArrayList<>();

    int index = -1;

    /**
     * 就一步步实现呗
     * @param nums
     * @return
     */
    public List> permute(int[] nums) {

        List numList = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
            numList.add(nums[i]);
            integerListTmp.add(nums[i]);
        }
        index = nums.length;
        permute(numList);
        return integerList;
    }

    public void permute(List numList) {
        int sizes = numList.size();
        if (sizes <= 0) {
            return ;
        }
        for (int i = 0; i < sizes; i++) {
            integerListTmp.set(index- sizes,numList.get(i));
            if(sizes <= 1){
                List numListTmp0 = new ArrayList<>();
                numListTmp0.addAll(integerListTmp);
                integerList.add(numListTmp0);
                return;
            }
            List numListTmp = new ArrayList<>();
            numListTmp.addAll(numList);
            numListTmp.remove(i);
            permute(numListTmp);
        }
    }
}

时间复杂度为

运行结果:

【程序94】
给定一个可包含重复数字的序列,返回所有不重复的全排列。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 给定一个可包含重复数字的序列,返回所有不重复的全排列。
 */
public class Subject94 {
    public static void main(String[] args) {
        int[] arrInt = new int[]{3,1,3,3};
        List> integerList1 = new Subject94().permuteUnique(arrInt);
        System.out.println(integerList1);
    }

    List> integerList = new ArrayList<>();
    List integerListTmp = new ArrayList<>();

    int index = -1;

    /**
     * 使用排序后,
     * 剪枝的方式实现。
     * @param nums
     * @return
     */
    public List> permuteUnique(int[] nums) {
        List numList = new ArrayList<>();
        //排序
        Arrays.sort(nums);

        for (int i = 0; i < nums.length; i++) {
            numList.add(nums[i]);
            integerListTmp.add(nums[i]);
        }
        index = nums.length;
        permuteUnique(numList);
        return integerList;
    }

    public void permuteUnique(List numList) {
        int sizes = numList.size();
        if (sizes <= 0) {
            return ;
        }
        Map map = new HashMap<>();
        for (int i = 0; i < sizes; i++) {
            Integer integer = map.get(index- sizes);
            if(integer != null){
                if(integer == numList.get(i)){  //多余的分支都剪掉
                    continue;
                }else{
                    map.put(index- sizes,numList.get(i));
                }
            }else{
                map.put(index- sizes,numList.get(i));
            }

            if(integerListTmp.get(index- sizes) != numList.get(i)){
                integerListTmp.set(index- sizes,numList.get(i));
            }
            if(sizes <= 1){
                List numListTmp0 = new ArrayList<>();
                numListTmp0.addAll(integerListTmp);
                integerList.add(numListTmp0);
                return;
            }
            List numListTmp = new ArrayList<>();
            numListTmp.addAll(numList);
            numListTmp.remove(i);
            permuteUnique(numListTmp);
        }
    }
}

时间复杂度为

运行结果:

【程序95】
给定一个 n×n 的二维矩阵表示一个图像。
将图像顺时针旋转 90 度。
说明:
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。

/**
 * 给定一个 n×n 的二维矩阵表示一个图像。
 * 将图像顺时针旋转 90 度。
 * 说明:
 * 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
 */
public class Subject95 {
    public static void main(String[] args) {
        int[][] arrInt = new int[][]{{1,2,3},{4,5,6},{7,8,9}};
        new Subject95().rotate(arrInt);
        System.out.println(arrInt);
    }

    public void rotate(int[][] matrix) {
        int n = matrix.length;
        for (int i = 0; i < (n + 1) / 2; i ++) {
            for (int j = 0; j < n / 2; j++) {
                int temp = matrix[n - 1 - j][i];
                matrix[n - 1 - j][i] = matrix[n - 1 - i][n - j - 1];
                matrix[n - 1 - i][n - j - 1] = matrix[j][n - 1 -i];
                matrix[j][n - 1 - i] = matrix[i][j];
                matrix[i][j] = temp;
            }
        }
    }
}

时间复杂度为 O(n^2)。

运行结果:

【程序96】
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"],
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
说明:
所有输入均为小写字母。
不考虑答案输出的顺序。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
 * 示例:
 * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"],
 * 输出:
 * [
 * ["ate","eat","tea"],
 * ["nat","tan"],
 * ["bat"]
 * ]
 * 说明:
 * 所有输入均为小写字母。
 * 不考虑答案输出的顺序。
 */
public class Subject96 {
    public static void main(String[] args) {
        String[] strArr = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"};
        List> listList = new Subject96().groupAnagrams(strArr);
        System.out.println(listList);
    }

    List> listList = new ArrayList<>();
    Map> map = new HashMap<>();
    public List> groupAnagrams(String[] strs) {
        for (int i = 0; i < strs.length; i++) {
            char[] ch = strs[i].toCharArray();
            String str = dealChar(ch);
            if(map.get(str) == null){
                List list = new ArrayList<>();
                list.add(strs[i]);
                map.put(str,list);
            }else{
                List list = map.get(str);
                list.add(strs[i]);
            }
        }

        Iterator>> it=map.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry> entry=it.next();
            listList.add(entry.getValue());
        }

        return listList;
    }

    public String dealChar(char[] ch) {
        Arrays.sort(ch);
        return new String(ch,0,ch.length);
    }
}

时间复杂度为 O(nk)。

运行结果:

【程序97】
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [?2^31, 2^31 ? 1] 。

import java.util.HashMap;
import java.util.Map;

/**
 * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。
 * -100.0 < x < 100.0
 * n 是 32 位有符号整数,其数值范围是 [?2^31, 2^31 ? 1] 。
 */
public class Subject97 {

    public static void main(String[] args) {
        double dou = new Subject97().myPow(1.13183,-2147483648);
        System.out.println(dou);
    }

    Map map = new HashMap<>();

    public double myPow(double x, int n) {
        double dou = 1.0;

        if(n > 0){
            if(n < 10){
                for (int i =0 ;i < n; i++){
                    dou = dou*x ;
                }
            }else{
                map.put(1,x);
                map.put(2,x*x);
                map.put(4,x*x*x*x);
                map.put(8,x*x*x*x*x*x*x*x);

                int index = 8;
                while(index <= n/2 && index < 1073741824){
                    int tmp = index;
                    index = index*2;
                    map.put(index,map.get(tmp)* map.get(tmp));
                }

                dou = map.get(index);
                int surplus = n - index;
                while(surplus > 0){
                    index = index/2;
                    if(surplus >= index){
                        dou = dou*map.get(index);
                    }else{
                        continue;
                    }
                    surplus = surplus - index;
                    if(index == 1){
                        break;
                    }
                }
            }

        }else if(n == 0){
            return 1;
        }else{
            if(n > -10){
                for (int i =0 ;i < -n; i++){
                    dou = dou*(1.0/x) ;
                }
            }else{
                map.put(-1,1.0/x);
                map.put(-2,(1.0/x)*(1.0/x));
                map.put(-4,(1.0/x)*(1.0/x)*(1.0/x)*(1.0/x));
                map.put(-8,(1.0/x)*(1.0/x)*(1.0/x)*(1.0/x)*(1.0/x)*(1.0/x)*(1.0/x)*(1.0/x));

                int index = -8;
                while(index >= n/2 ){
                    int tmp = index;
                    index = index*2;
                    map.put(index,map.get(tmp)* map.get(tmp));
                }

                dou = map.get(index);
                int surplus = n - index;
                while(surplus < 0){
                    index = index/2;
                    if(surplus <= index){
                        dou = dou*map.get(index);
                    }else{
                        continue;
                    }
                    surplus = surplus - index;
                    if(index == -1){
                        break;
                    }
                }
            }
        }
        return dou;
    }
}

时间复杂度为 O(n)。

运行结果:

以上题目均来自:https://leetcode-cn.com/ ,如果你热爱编码,热爱算法,该网站一定适合你。

你可能感兴趣的:(《Java练习题》进阶练习题(五))