《Java练习题》Java进阶练习题(一)
编程合集: https://www.cnblogs.com/jssj/p/12002760.html
前言:不仅仅要实现,更要提升性能,精益求精,用尽量少的时间复杂度和空间复杂度解决问题。
【程序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/ ,如果你热爱编码,热爱算法,该网站一定适合你。