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

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

【程序48】
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标

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

/**
 * 【程序48】
 * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标
 */
public class Subject48 {
    public static void main(String[] args) {
        int[] nums = new int[]{1,4,5,6,7,9,76,43,22,11};
        int target = 11;
        int[] result = twoSum(nums,target);
        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);
        }
    }

    /**
     * 获取满足条件的数组下标
     * @param nums
     * @param target
     */
    private static int[] twoSum(int[] nums, int target) {
        int[] temp = new int[2];
        Map<Integer,Integer> map = new HashMap<>();
        //遍历查找
        for(int i = 0; i < nums.length; i++){
            int a = nums[i];
            //判断键值是否存在
            if(map.containsKey(target - a)){
                temp[0] = map.get(target - a);
                temp[1] = i;
                return temp;
            }else {//如果找不到则存进去
                map.put(nums[i], i);
            }
        }
        return null;
    }
}

时间复杂度为 O(n)。

运行结果:

【程序49】
给出两个非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0开头。

public class ListNode {
    int val;
    ListNode next;
    ListNode(){

    }
    ListNode(int x) { val = x; }
}
/**
 * 【程序49】
 * 给出两个非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字。
 * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
 * 您可以假设除了数字 0 之外,这两个数都不会以 0开头。
 *
 * public class ListNode {
 * int val;
 * ListNode next;
 * ListNode(int x) { val = x; }
 }
 */
public class Subject49 {
    public static void main(String[] args) {
        ListNode l1 = new ListNode(2);
        ListNode l12 = new ListNode(4);
        ListNode l13 = new ListNode(3);
        l1.next = l12;
        l12.next = l13;

        ListNode l2 = new ListNode(5);
        ListNode l21 = new ListNode(6);
        ListNode l22 = new ListNode(4);
        l2.next = l21;
        l21.next = l22;

        ListNode listNode = addTwoNumbers(l1,l2);
        StringBuilder stringBuilder = null;
        while(listNode !=null){  //指向位置是否为空
            if(stringBuilder == null){
                stringBuilder = new StringBuilder();
                stringBuilder.append(listNode.val);
            }else{
                stringBuilder.append(" -> "+ listNode.val);
            }
            listNode = listNode.next;    // 指向下一个节点
        }
        System.out.println(stringBuilder.toString());
    }

    /**
     * 链表输出和
     * @param l1
     * @param l2
     * @return
     */
    public static ListNode addTwoNumbers(ListNode l1, ListNode l2){
        int carry = 0;   //进位
        ListNode newListNode = new ListNode(0);
        ListNode tmpListNode ;
        tmpListNode = newListNode;
        while(true){
            ListNode listNode = new ListNode(0);
            int tmp = l1.val + l2.val + carry;
            if(tmp < 10){
                listNode.val = tmp;
                carry = 0;
            }else{
                listNode.val = tmp%10;
                carry = 1;
            }
            tmpListNode.next = listNode;
            tmpListNode = listNode;
            if(l1.next ==null && l2.next == null &&carry == 0){
                break;
            }
            if(l1.next != null){
                l1 = l1.next;
            }else{
                l1 = new ListNode(0);
            }
            if( l2.next != null){
                l2 = l2.next;
            }else{
                l2 = new ListNode(0);
            }
        }
        return newListNode.next;
    }
}

时间复杂度:O(\max(m, n))

运行结果:

【程序50】
给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。

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

/**
 * 给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
 */
public class Subject50 {
    public static void main(String[] args) {
        String Str = "aabcdfffwwesdwhjkl";
        int count = lengthOfLongestSubstring(Str);
        System.out.println(count);
    }

    /**
     * 获取字符最大长度
     * @param s
     * @return
     */
    public static int lengthOfLongestSubstring(String s) {
        char[] arr = s.toCharArray();
        List<Character> list = new ArrayList<>();
        int maxCount = 0;
        int count;
        for (int i = 0; i < arr.length; i++) {
            if(list.contains(arr[i])){
                count = list.size();
                if(count> maxCount){
                    maxCount = count;
                }
                for (int j = 0; j < list.size(); j++) {
                    if(list.get(j) != arr[i]){
                        list.remove(j);
                        j--;
                    }else{
                        list.remove(j);
                        break;
                    }
                }
                list.add(arr[i]);
            }else{
                list.add(arr[i]);
            }
        }
        if(list.size() > maxCount){
            return list.size();
        }else{
            return maxCount;
        }
    }
}

时间复杂度:O(n)

运行结果:

【程序51】
给定两个大小为 m 和 n 的有序数组nums1 和nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为O(log(m + n))。
你可以假设nums1和nums2不会同时为空

/**
 * 给定两个大小为 m 和 n 的有序数组nums1 和nums2。
 * 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为O(log(m + n))。
 * 你可以假设nums1和nums2不会同时为空
 */
public class Subject51 {
    public static void main(String[] args) {
        int[] nums1 = new int[]{1,2,3};
        int[] nums2 = new int[]{1,2};
        double arr = findMedianSortedArrays(nums1,nums2);
        System.out.println(arr);
    }

    public static int PartSort(int arr[], int low, int high) {
        int data = arr[low];
        /**一次遍历的方法:插空法 定义一个data将arr[low]存起来,并把这个位置挖空*/
        while (low < high) {
            while (low < high && arr[high] >= data) {
                high--;
            }
            arr[low] = arr[high];
            /**从high,也就是后面往前遍历 找到比键值小的数据 插入到前面留下的空中 high位再次留下空来*/
            while (low < high && arr[low] <= data) {
                low++;
            }
            arr[high] = arr[low];
        }
        arr[low] = data;
        /**循环退出后 low和high重合 将将键值赋给第low,并将low返回*/
        return low;
    }


    /**
     * 快速排序法
     * @param arr
     * @param low
     * @param high
     */
    public static void quickSort(int arr[], int low, int high) {
        if(low<high) {
            //防止发生栈溢出异常
            int index = PartSort(arr, low, high);
            quickSort(arr, low, index - 1);
            quickSort(arr, index + 1, high);
        }
    }

    /**
     * 寻找中位数
     * @param nums1
     * @param nums2
     * @return
     */
    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int a = nums1.length;
        int b = nums2.length;
        int[] arr = new int[a+b];
        double result = 0.0;
        if(a >= 2 && b >=2 ){
            if(nums1[0] <= nums1[1] && nums2[0] <= nums2[1] ){
                if(nums1[0] >= nums2[0]){
                    for (int i = 0; i < b; i++) {
                        arr[i] = nums2[i];
                    }
                    for (int i = 0; i < a; i++) {
                        arr[i+b] = nums1[i];
                    }
                }else{
                    for (int i = 0; i < a; i++) {
                        arr[i] = nums1[i];
                    }
                    for (int i = 0; i < b; i++) {
                        arr[i+a] = nums2[i];
                    }
                }
            }else if(nums1[0] >= nums1[1] && nums2[0] >= nums2[1]){
                if(nums1[a-1] <= nums2[b-1]){
                    for (int i = 0; i < a; i++) {
                        arr[i] = nums1[a-i-1];
                    }
                    for (int i = 0; i < b; i++) {
                        arr[i+a] = nums2[b-i-1];
                    }
                }else{
                    for (int i = 0; i < b; i++) {
                        arr[i] = nums1[b-i-1];
                    }
                    for (int i = 0; i < a; i++) {
                        arr[i+b] = nums2[a-i-1];
                    }
                }
            }else if(nums1[0] <= nums1[1] && nums2[0] >= nums2[1]){
                if(nums1[0] <= nums2[b-1]){
                    for (int i = 0; i < a; i++) {
                        arr[i] = nums1[i];
                    }
                    for (int i = 0; i < b; i++) {
                        arr[i+a] = nums2[b-i-1];
                    }
                }else{
                    for (int i = 0; i < b; i++) {
                        arr[i] = nums2[i];
                    }
                    for (int i = 0; i < a; i++) {
                        arr[i+b] = nums1[a-1-i];
                    }
                }
            }else if(nums1[0] >= nums1[1] && nums2[0] <= nums2[1]){
                if(nums1[a-1] <= nums2[0]){
                    for (int i = 0; i < a; i++) {
                        arr[i] = nums1[a-1-i];
                    }
                    for (int i = 0; i < b; i++) {
                        arr[i+a] = nums2[i];
                    }
                }else{
                    for (int i = 0; i < b; i++) {
                        arr[i] = nums2[i];
                    }
                    for (int i = 0; i < a; i++) {
                        arr[i+b] = nums1[a-1-i];
                    }
                }
            }
        }else{
            for (int i = 0; i < a; i++) {
                arr[i] = nums1[i];
            }
            for (int i = 0; i < b; i++) {
                arr[i+a] = nums2[i];
            }
        }
        int right = arr.length-1;
        int left = 0;

        quickSort(arr,left,right);

        int tmp = arr.length;
        if(tmp % 2 == 0){
            result = (arr[tmp/2] + arr[tmp/2 - 1]) / 2.0;
        }else{
            result = arr[tmp/2];
        }
        return result;
    }
}

时间复杂度:O(log(min(m,n)))

运行结果:

【程序52】
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

/**
 * 【程序52】
 * 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
 */
public class Subject52 {
    public static void main(String[] args) {
        String str = "sdffttrrgfddfh";
        String result= longestPalindrome(str);
        System.out.println(result);
        result = longestPalindrome1(str);
        System.out.println(result);
    }

    /**
     * Manacher算法
     * @param str
     * @return
     */
    private static String longestPalindrome1(String str) {
        char[] cStr = str.toCharArray();
        //插入特殊符号
        StringBuffer sBuffer = new StringBuffer();
        sBuffer.append("#");
        for (int i = 0; i < cStr.length; i++) {
            sBuffer.append(cStr[i]);
            sBuffer.append("#");
        }
        int id =0;   //回文的中心。
        int max = 0; //回文最大长度。
        //辅助数组
        int[] p= new int[sBuffer.length()];
        for (int i = 1; i < sBuffer.length(); i++) {

            if (i<max) {
                p[i] = Math.min(p[2*id-i], max-i);
            }else {
                p[i]= 1;
            }
            //判断中心两边是否回文,是则++;
            while (i-p[i]>=0&&i+p[i]<sBuffer.length()&&sBuffer.charAt(i-p[i])==sBuffer.charAt(i+p[i])) {
                p[i]++;
            }
            if (i+p[i]>max) {
                max = i+p[i];
                id = i;
            }
        }
        int maxl = 0 ;
        int maxid =0 ;
        for(int i =0 ;i<p.length;i++){
            if(maxl<p[i]){
                maxl=p[i];
                maxid = i;
            }
        }
        //半径包括id本身。id到第一个元素,id-r+1
        int r = maxl-1;
        int start = maxid-r+1;
        int end = maxid+maxl-1;
        StringBuffer out = new StringBuffer();
        for (int i = start; i < end; i++) {
            if (sBuffer.charAt(i)!='#') {
                out.append(sBuffer.charAt(i));
            }
        }
        return out.toString();
    }


    /**
     * 获取最长回文数
     * @param s
     * @return
     */
    public static String longestPalindrome(String s) {
        String result = "";
        char[] arr = s.toCharArray();
        for(int i = 0 ; i < arr.length; i++){
            for (int j = 0; j <= i; j++) {
                //判断是否回文。
                result =  palindromeStr(s,arr,i,j);
                if(!"".equals( result) ){
                    return result;
                }
            }
        }
        return result;
    }

    /**
     * 判断字符串是否是回文字符串
     * @param s
     * @param arr
     * @param i
     * @param j
     * @return
     */
    private static String palindromeStr(String s,char[] arr, int i, int j) {
        String result = "";
        int start = j;
        int end = arr.length-(i-j)-1;
        while(start <= end){
            if(arr[start] == arr[end]){
                if(start+1 >= end){
                    result = s.substring(j,arr.length-(i-j));
                    return result;
                }
                start++;
                end--;
            }else{
                break;
            }
        }
        return result;
    }
}

时间复杂度:O(n

运行结果:

【程序53】
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 |\| 字形排列

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

/**
 * 【程序53】
 * 将一个给定字符串根据给定的行数,以从上往下、从左到右进行  字形排列
 *
 * 输入: s = "LEETCODEISHIRING", numRows =4
 * 输出:"LDREOEIIECIHNTSG"
 * 解释:
 *   L     D     R
 *   E   O E   I I
 *   E C   I H   N
 *   T     S     G
 */
public class Subject53 {
    public static void main(String[] args) {
        String s = "LEETCODEISHIRING";
        int numRows = 4;
        String str = convert(s,numRows);
        System.out.println(str);
    }

    /**
     *
     * @param s
     * @param numRows
     * @return
     */
    public static String convert(String s,int numRows){
        if(numRows <= 1){
            return s;
        }
        char[] arr = s.toCharArray();
        //创建numRows个字符串
        List<StringBuilder> list = new ArrayList<>();
        for (int i = 0; i < numRows; i++) {
            StringBuilder stringBuffer = new StringBuilder();
            list.add(stringBuffer);
        }

        int flag = 0; // 0表示顺序,1表示逆序。
        int size = 1; //在第几行
        for (int i = 0; i < arr.length; i++) {
            if(size == numRows){
                flag = 1;
            }
            if(size == 1){
                flag = 0;
            }
            list.get(size-1).append(arr[i]);

            if(flag == 0){
                size++;
            }
            if(flag == 1){
                size--;
            }
        }

        StringBuilder newStringBuffer = new StringBuilder();

        for (int i = 0; i < numRows; i++) {
            newStringBuffer.append(list.get(i));
        }
        return newStringBuffer.toString();
    }
}

时间复杂度:O(n)

运行结果:

【程序54】
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

/**
 * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
 */
public class Subject54 {
    public static void main(String[] args) {
        int x= 2147483641;
        int result = reverse(x);
        System.out.println(result);
        result = reverse2(x);
        System.out.println(result);
    }

    /**
     * 反转
     * @param x
     * @return
     */
    public static int reverse(int x){
        String str = x+"";
        char[] arr = str.toCharArray();
        StringBuilder  stringBuilder =  new StringBuilder();
        if(arr[0] == '-'){
            stringBuilder.append('-');
            for (int i = arr.length-1; i >= 1; i--) {
                stringBuilder.append(arr[i]);
            }
        }else{
            for (int i = arr.length-1; i >= 0; i--) {
                stringBuilder.append(arr[i]);
            }
        }

        int result = 0;
        try {
            result = Integer.parseInt(stringBuilder.toString());
        }catch (Exception e){
            result = 0;
        }
        return result;
    }

    /**
     * 反转2
     * @param x
     * @return
     */
    public static int reverse2(int x){
        int rev = 0;
        while (x != 0) {
            int pop = x % 10;
            x /= 10;
            if (rev > Integer.MAX_VALUE/10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
            if (rev < Integer.MIN_VALUE/10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
            rev = rev * 10 + pop;
        }
        return rev;
    }
}

时间复杂度:O(\log(x))

运行结果:

【程序55】
请你来实现一个 atoi 函数,使其能将字符串转换成整数。

/**
 * 【程序55】
 * 请你来实现一个 atoi 函数,使其能将字符串转换成整数。
 */
public class Subject55 {
    public static void main(String[] args) {
        String str = " -2147483649ww";
        int i= myAtoi(str);
        System.out.println(i);
    }
    public static int myAtoi(String str) {
        int radix = 10;
        if (str == null) {
            return 0;
        }else{
            str = str.trim();
        }

        int result = 0;
        boolean negative = false;
        int i = 0, len = str.length();
        int limit = -Integer.MAX_VALUE;
        int multmin;
        int digit;

        if (len > 0) {
            char firstChar = str.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    return 0;

                if (len == 1) // Cannot have lone "+" or "-"
                    return 0;
                i++;
            }
            multmin = limit / radix;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(str.charAt(i++),radix);
                if (digit < 0) {
                    break;
                }
                if (result < multmin) {
                    result = limit;
                    break;
                }
                result *= radix;
                if (result < limit + digit) {
                    result = limit;
                    break;
                }
                result -= digit;
            }
        } else {
            return 0;
        }
        return negative ? result : -result;
    }
}

时间复杂度:O(n)

运行结果:

【程序56】
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
考虑负数。

/**
 * 【程序56】
 * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
 */
public class Subject56 {
    public static void main(String[] args) {
        int x = 1;
        boolean flag = isPalindrome(x);
        System.out.println(flag);
    }

    /**
     * 判断x是否是回文数
     * @param x
     * @return
     */
    public static boolean isPalindrome(int x) {
        if(x < 0){
            return false;
        }
        if(x < 10){
            return true;
        }
        int newi = 0;
        int num = x;
        while(true){
            if(newi>0){
                newi = newi*10;
            }
            int i = num%10 ;
            newi = newi+i;
            num = num/10;
            if(num <= 9){
                newi = newi*10+num;
                break;
            }
        }
        if(newi == x){
            return true;
        }else{
            return false;
        }
    }
}

时间复杂度:O(\log_{10}(n))

运行结果:

【程序57】
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素

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

/**
 * 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
 * '.' 匹配任意单个字符
 * '*' 匹配零个或多个前面的那一个元素
 */
public class Subject57 {
    public static void main(String[] args) {
        Map<String ,String>  map = new HashMap<>();
        map.put("dddc","d*dddc");    //true;
        for (Map.Entry<String,String> entry :map.entrySet()){
            System.out.println(entry.getKey()+" : "+entry.getValue());
            System.out.println(isMatch(entry.getKey(),entry.getValue()));
        }
    }

    /**
     * 实现匹配规则
     * @param s
     * @param p
     * @return
     */
    public static boolean isMatch(String s, String p) {
        if (p.isEmpty()) return s.isEmpty();
        boolean first_match = (!s.isEmpty() &&
                (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'));

        if (p.length() >= 2 && p.charAt(1) == '*'){
            return (isMatch(s, p.substring(2)) ||
                    (first_match && isMatch(s.substring(1), p)));
        } else {
            return first_match && isMatch(s.substring(1), p.substring(1));
        }
    }
}

时间复杂度:O(TP)

运行结果:

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

猜你喜欢

转载自www.cnblogs.com/jssj/p/12001585.html