From ebbaae5e7f0a61435b99371cf8b20d166471641b Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Fri, 31 Mar 2023 15:06:24 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataStructures/pom.xml | 27 ++ .../com/atguigu/sort/selftry/HeapSort.java | 73 ++++++ .../main/java/com/atguigu/tree/HeapSort.java | 53 ++-- .../leecode/hot100/T78_LengthOfLIS.java | 72 ++++++ .../hot100/T79_RemoveInvalidParentheses.java | 241 ++++++++++++++++++ .../leecode/hot100/T80_MaxProfit.java | 70 +++++ .../markilue/leecode/hot100/T81_MaxCoins.java | 120 +++++++++ .../java/com/markilue/leecode/test/test.java | 10 + .../com/markilue/leecode/test/testAnt.java | 155 +++++++---- 9 files changed, 758 insertions(+), 63 deletions(-) create mode 100644 DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/sort/selftry/HeapSort.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T78_LengthOfLIS.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T79_RemoveInvalidParentheses.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java diff --git a/DataStructures_Algorithm/DataStructures/pom.xml b/DataStructures_Algorithm/DataStructures/pom.xml index e36fa45..ea4b98b 100644 --- a/DataStructures_Algorithm/DataStructures/pom.xml +++ b/DataStructures_Algorithm/DataStructures/pom.xml @@ -9,6 +9,33 @@ 4.0.0 + + + junit + junit + 4.13.2 + test + + + junit + junit + 4.13.2 + compile + + + org.projectlombok + lombok + RELEASE + compile + + + junit + junit + 4.13.1 + compile + + + DataStructures diff --git a/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/sort/selftry/HeapSort.java b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/sort/selftry/HeapSort.java new file mode 100644 index 0000000..21d506c --- /dev/null +++ b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/sort/selftry/HeapSort.java @@ -0,0 +1,73 @@ +package com.atguigu.sort.selftry; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: DataStructures_Algorithm + *@BelongsPackage: com.atguigu.sort.selftry + *@Author: markilue + *@CreateTime: 2023-03-31 10:26 + *@Description: TODO 尝试堆排序 + *@Version: 1.0 + */ +public class HeapSort { + + @Test + public void test(){ + int[] arr = {20, 50, 45, 40, 35,10,30,15,25}; + //测试80000个数据进行测试 +// int[] arr = new int[200]; +// for (int i = 0; i < arr.length; i++) { +// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数 +// } + heapSort(arr); + System.out.println(Arrays.toString(arr)); + } + + + public void heapSort(int[] arr) { + + if (arr == null) return; + //从最后一个非叶子节点开始进行堆化 + for (int i = arr.length / 2 - 1; i >= 0; i--) { + adjustHeap(arr, i, arr.length); + } + + //进行交换 + int temp; + for (int i = arr.length - 1; i > 0; i--) { + temp = arr[i]; + arr[i] = arr[0]; + arr[0] = temp; + adjustHeap(arr, 0, i);//把交换完的i放在合适的位置 + } + + + } + + public void adjustHeap(int[] arr, int i, int length) { + + int temp = arr[i];//记录下以前位置的值 + + for (int j = 2 * i + 1; j < length; j++) { + //比较左右节点哪一个更大 + if (j + 1 < length && arr[j] < arr[j + 1]) { + j++; + } + if (arr[j] > temp) { + //需要进行交换 + arr[i] = arr[j]; + i = j;//后续比较j位置的值了 + } else { + break; + } + } + arr[i] = temp;//找到合适的位置放temp + + + } + + +} diff --git a/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java index 2169512..8b2682a 100644 --- a/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java +++ b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java @@ -1,5 +1,7 @@ package com.atguigu.tree; +import org.junit.Test; + import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; @@ -17,44 +19,57 @@ public class HeapSort { // System.out.println(Arrays.toString(arr)); //测试80000个数据进行测试 - int[] arr =new int[8000000]; + int[] arr = new int[8000000]; for (int i = 0; i < arr.length; i++) { - arr[i] = (int)(Math.random()*8000000); //生成一个[0,80000]的数 + arr[i] = (int) (Math.random() * 8000000); //生成一个[0,80000]的数 } Date date1 = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String date1Str = simpleDateFormat.format(date1); - System.out.println("排序前的时间:"+date1Str); //排序前的时间:2022-02-15 21:19:36 + System.out.println("排序前的时间:" + date1Str); //排序前的时间:2022-02-15 21:19:36 heapSort(arr); Date date2 = new Date(); String date2Str = simpleDateFormat.format(date2); - System.out.println("排序后的时间:"+date2Str); //排序后的时间:2022-02-15 21:19:40 + System.out.println("排序后的时间:" + date2Str); //排序后的时间:2022-02-15 21:19:40 } + @Test + public void test() { + int[] arr = {20, 50, 45, 40, 35,10,30,15,25}; + //测试80000个数据进行测试 +// int[] arr = new int[200]; +// for (int i = 0; i < arr.length; i++) { +// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数 +// } + heapSort(arr); + System.out.println(Arrays.toString(arr)); + } + /** * 编写一个堆排序的方法 */ public static void heapSort(int[] arr) { //TODO (1)将无序序列构建成一个堆,根据升序降序需求选择大顶堆或者小顶堆 - //arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点 - for (int i = arr.length/2-1; i >= 0; i--) { - adjustHeap(arr,i,arr.length); + // arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点; + // arr.length/2-1是关键,是adjustHeap前提的满足条件的前提 + for (int i = arr.length / 2 - 1; i >= 0; i--) { + adjustHeap(arr, i, arr.length); } - int temp=0; + int temp = 0; //TODO (2)将顶对元素与末尾元素交换,将最大元素放置在数组末尾 - //TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,贩毒执行调整+交换步骤,直到整个序列有序 - for (int i = arr.length-1; i >0; i--) { + //TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序 + for (int i = arr.length - 1; i > 0; i--) { //交换 - temp=arr[i]; - arr[i]=arr[0]; - arr[0]=temp; - adjustHeap(arr,0,i); + temp = arr[i]; + arr[i] = arr[0]; + arr[0] = temp; + adjustHeap(arr, 0, i);//主要就是利用堆顶元素就是最大值来进行处理的 } @@ -62,7 +77,7 @@ public class HeapSort { } /** - * 前提:该节点的所有子节点都已经是大顶堆了 + * TODO 前提:该节点的所有子节点都已经是大顶堆了,因为这里需要break * 将以第i个位置为根节点时以下树,调整成一个大顶堆 * * @param arr 待调整的数组 @@ -76,20 +91,22 @@ public class HeapSort { //开始调整 //说明:j = i * 2 + 1 ;这里k就是i节点的左子节点 for (int j = i * 2 + 1; j < length; j = j * 2 + 1) { + //TODO 1.寻找左右节点哪一个更大 if (j + 1 < length && arr[j] < arr[j + 1]) { //左子节点的值小于右子节点的值 j++; //j指向右子节点 } + //TODO 2.用左右节点中大值去和他的父节点比较;如果小了直接将父节点变成那个最大的值 if (arr[j] > temp) { //如果子节点大于父节点 arr[i] = arr[j];//把较大的值赋给当前节点 i = j; //将i指向j,继续循环比较 - }else { - break; + } else { + break;//左右子节点都比父节点小,直接break } } //当for循环结束后,我们已经将以i为父节点的树的最大值,放在了i的位置 - arr[i]=temp; //将temp值放在调整后的位置 + arr[i] = temp; //将temp值放在调整后的位置 } diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T78_LengthOfLIS.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T78_LengthOfLIS.java new file mode 100644 index 0000000..32d2281 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T78_LengthOfLIS.java @@ -0,0 +1,72 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-30 10:14 + *@Description: + * TODO 力扣300 最长递增子序列: + * 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 + * 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 + *@Version: 1.0 + */ +public class T78_LengthOfLIS { + + @Test + public void test() { +// int[] nums={10,9,2,5,3,7,101,18}; + int[] nums = {1, 3, 6, 7, 9, 4, 10, 5, 6}; + System.out.println(lengthOfLIS(nums)); + } + + /** + * 思路:dp + * dp[i]表示以0开头以i结尾的数组的最长递增子序列长度 + * @param nums + * @return + */ + public int lengthOfLIS(int[] nums) { + + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + int max = 0; + + + for (int i = 1; i < dp.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + if (max < dp[i]) max = dp[i]; + } + } + return max; + } + + + public int lengthOfLIS1(int[] nums) { + int N = nums.length; + //end[i]表示i+1长度的递增子序列的最小值 + int[] end = new int[N]; + end[0] = nums[0]; + int index = 0; + for(int i=1; i< N;i++){ + if(nums[i] > end[index]){ + end[++index] = nums[i]; + } else { + for (int j = 0; j <= index; j++) { + if (nums[i] <= end[j]) { + end[j] = nums[i];//替换对应的位置 + break; + } + } + } + } + return index + 1; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T79_RemoveInvalidParentheses.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T79_RemoveInvalidParentheses.java new file mode 100644 index 0000000..165d2f9 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T79_RemoveInvalidParentheses.java @@ -0,0 +1,241 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-30 10:36 + *@Description: + * TODO 力扣301 删除无效的括号: + * 给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。 + * 返回所有可能的结果。答案可以按 任意顺序 返回。 + *@Version: 1.0 + */ +public class T79_RemoveInvalidParentheses { + + + //不知道该怎么去重,就用set存储结果 18ms + Set set = new HashSet<>(); + StringBuilder str; + + public List removeInvalidParentheses(String s) { + int lmove = 0; + int rmove = 0; + str = new StringBuilder(s); + //遍历一遍,求出要删除左括号和右括号的数量 + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + lmove++; + } else if (s.charAt(i) == ')') { + //左右括号可以匹配 + if (lmove > 0) { + lmove--; + } else { + rmove++; + } + } + } + dfs(lmove, rmove, 0); + return new ArrayList<>(set); + } + + public void dfs(int lmove, int rmove, int i) { + if (lmove == 0 && rmove == 0) { + //判断字符串内括号是否有效 + if (isValid(str)) { + set.add(new String(str.toString())); + } + return; + } + //还需要删除的括号个数 小于 能过删除的字符个数 + if (lmove + rmove > str.length() - i) { + return; + } + //不删除 + dfs(lmove, rmove, i + 1); + + //删除,分左右括号考虑 + if (str.charAt(i) == '(' && lmove > 0) { + str.deleteCharAt(i);//删除 + dfs(lmove - 1, rmove, i);//进入下一层,因为删除了i处括号,所以不需要i+1 + str.insert(i, '(');//恢复现场 + } else if (str.charAt(i) == ')' && rmove > 0) { + str.deleteCharAt(i);//删除 + dfs(lmove, rmove - 1, i);//进入下一层 + str.insert(i, ')');//恢复现场 + } + } + + public boolean isValid(StringBuilder str) { + int left = 0; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '(') { + left++; + } else if (str.charAt(i) == ')') { + left--; + } + if (left < 0) { + return false; + } + } + return true; + } + + + //自己去重4ms + private List res = new ArrayList(); + + public List removeInvalidParentheses1(String s) { + int lremove = 0; + int rremove = 0; + + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + lremove++; + } else if (s.charAt(i) == ')') { + if (lremove == 0) { + rremove++; + } else { + lremove--; + } + } + } + helper(s, 0, lremove, rremove); + + return res; + } + + private void helper(String str, int start, int lremove, int rremove) { + if (lremove == 0 && rremove == 0) { + if (isValid(str)) { + res.add(str); + } + return; + } + + for (int i = start; i < str.length(); i++) { + if (i != start && str.charAt(i) == str.charAt(i - 1)) { + continue; + } + // 如果剩余的字符无法满足去掉的数量要求,直接返回 + if (lremove + rremove > str.length() - i) { + return; + } + // 尝试去掉一个左括号 + if (lremove > 0 && str.charAt(i) == '(') { + helper(str.substring(0, i) + str.substring(i + 1), i, lremove - 1, rremove); + } + // 尝试去掉一个右括号 + if (rremove > 0 && str.charAt(i) == ')') { + helper(str.substring(0, i) + str.substring(i + 1), i, lremove, rremove - 1); + } + } + } + + private boolean isValid(String str) { + int cnt = 0; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '(') { + cnt++; + } else if (str.charAt(i) == ')') { + cnt--; + if (cnt < 0) { + return false; + } + } + } + + return cnt == 0; + } + + + @Test + public void test(){ + String s ="()())()"; + System.out.println(removeInvalidParentheses2(s)); + } + + + //自己尝试一遍 + public List removeInvalidParentheses2(String s) { + + //统计需要去掉的左括号和右括号的数量 + + int left = 0; + int right = 0; + + for (char c : s.toCharArray()) { + if (c == '(') { + left++; + } else if (c == ')') { + if (left == 0) { + right++; + } else { + left--; + } + } + } + helper1(s, left, right, 0); + return res; + + } + + public void helper1(String s, int left, int right, int start) { + if (left == 0 && right == 0) { + if (isValid1(s)) { + res.add(s); + } + return; + } + + for (int i = start; i < s.length(); i++) { + //去重 + if (i != start && s.charAt(i) == s.charAt(i - 1)) continue; + + if (left + right > s.length() - i) { + //怎么删都不够了 + return; + } + + //尝试删除左括号 + if (left > 0 && s.charAt(i) == '(') { + helper1(s.substring(0, i) + s.substring(i + 1), left - 1, right, i + 1); + } + + //尝试删除右括号 + if (right > 0 && s.charAt(i) == ')') { + helper1(s.substring(0, i) + s.substring(i + 1), left, right - 1, i + 1); + } + + + } + + } + + public boolean isValid1(String s) { + int left = 0; + for (char c : s.toCharArray()) { + if (c == '(') { + left++; + } else if (c == ')') { + if (left == 0) { + return false; + } else { + left--; + } + } + } + + return left==0; + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java new file mode 100644 index 0000000..5eb0bb0 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java @@ -0,0 +1,70 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-31 11:13 + *@Description: TODO + *@Version: 1.0 + */ +public class T80_MaxProfit { + + @Test + public void test() { + int[] prices = {1, 2, 3, 0, 2}; + System.out.println(maxProfit(prices)); + } + + + /** + * 动态dp,状态分为三种: + * 今天手里没有股票且不在冷冻期dp[i][0] + * 今天手里没有股票且在冷冻期dp[i][1] + * 今天手里有股票dp[i][2] + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + if (prices.length == 1) return 0; + + int[][] dp = new int[prices.length][3]; + + dp[0][0] = 0; + dp[0][1] = 0; + dp[0][2] = -prices[0]; + + for (int i = 1; i < prices.length; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);//昨天是冷冻期;或者昨天也没买 + dp[i][1] = dp[i - 1][2] + prices[i];//必须是今天买入 + dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][0] - prices[i]);//必须是今天买入 + } + + return Math.max(dp[dp.length - 1][0], dp[dp.length - 1][1]); + + } + + //滚动数组优化 + public int maxProfit1(int[] prices) { + if (prices.length == 1) return 0; + + + int dp0 = 0; + int dp1 = 0; + int dp2 = -prices[0]; + + for (int i = 1; i < prices.length; i++) { + int temp = dp0; + dp0 = Math.max(dp0, dp1);//昨天是冷冻期;或者昨天也没买 + dp1 = dp2 + prices[i];//必须是今天买入 + dp2 = Math.max(dp2, temp - prices[i]);//必须是今天买入 + } + + return Math.max(dp0, dp1); + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java new file mode 100644 index 0000000..db1eb47 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java @@ -0,0 +1,120 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-31 11:28 + *@Description: TODO + *@Version: 1.0 + */ +public class T81_MaxCoins { + + @Test + public void test() { + int[] nums = {3, 1, 5, 8}; + System.out.println(maxCoins1(nums)); + } + + + /** + * 思路:优先戳中间最小的 + * 不对 + * @param nums + * @return + */ + public int maxCoins(int[] nums) { + + int result = 0; + int count = nums.length; + + while (nums[0] != -1) { + int minIndex = 0; + int threshold = nums.length; + + if (count == 3) { + boolean flag = false; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == -1) { + threshold = i; + break; + } + if (nums[i] == 1) { + minIndex = i; + flag = true; + } + + } + if (!flag) { + minIndex = 1; + } + }else { + for (int i = 1; i < nums.length; i++) { + if (nums[i] == -1) { + threshold = i; + break; + } + if (nums[minIndex] > nums[i]) { + minIndex = i; + } + } + } + + + //戳i位置 + int left; + if (minIndex - 1 < 0) { + left = 1; + } else { + left = nums[minIndex - 1]; + } + + int right; + if (minIndex + 1 >= threshold) { + right = 1; + } else { + right = nums[minIndex + 1]; + } + result += left * nums[minIndex] * right; + System.arraycopy(nums, minIndex + 1, nums, minIndex, threshold - minIndex - 1); + nums[threshold - 1] = -1; + count--; + } + + return result; + + } + + + /** + * 官方动态规划法: + * dp[i][j]表示填满开区间(i,j)能得到的最多硬币数 + * 最终答案即为 dp[0][n+1]dp[0][n+1]dp[0][n+1]。实现时要注意到动态规划的次序。 + * 动态规划: + * 速度击败27.13% 内存击败45.56% 43ms + * @param nums + * @return + */ + public int maxCoins1(int[] nums) { + int n = nums.length; + int[][] rec = new int[n + 2][n + 2]; + int[] val = new int[n + 2]; + val[0] = val[n + 1] = 1; + for (int i = 1; i <= n; i++) { + val[i] = nums[i - 1]; + } + for (int i = n - 1; i >= 0; i--) { + for (int j = i + 2; j <= n + 1; j++) { + for (int k = i + 1; k < j; k++) { + int sum = val[i] * val[k] * val[j];//计算戳当前点的sum + sum += rec[i][k] + rec[k][j];//计算不要这个点之后的左右点的戳开的和 + rec[i][j] = Math.max(rec[i][j], sum); + } + } + } + return rec[0][n + 1]; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/test/test.java b/Leecode/src/main/java/com/markilue/leecode/test/test.java index b1e34e2..4e39125 100644 --- a/Leecode/src/main/java/com/markilue/leecode/test/test.java +++ b/Leecode/src/main/java/com/markilue/leecode/test/test.java @@ -15,6 +15,16 @@ import java.util.ArrayList; */ public class test { + static { + + + System.out.println("hello sta"); + } + + public static void main(String[] args) { + System.out.println("hello world"); + } + //测试ArrayList的index是否发生变化 @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java b/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java index 80406a4..0e7673b 100644 --- a/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java +++ b/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java @@ -1,6 +1,7 @@ package com.markilue.leecode.test; -import java.util.HashMap; +import java.util.*; + import java.util.Scanner; /** @@ -14,53 +15,53 @@ import java.util.Scanner; public class testAnt { - public static void main(String[] args) { - - Scanner sc = new Scanner(System.in); - String input = sc.nextLine(); - - new testAnt().test(input); -// StringBuilder output = new StringBuilder(); -// int left = 0; +// public static void main(String[] args) { // -// //去除前面的 -// while (left < input.length() && input.charAt(left) == ' ') { -// left++; -// } +// Scanner sc = new Scanner(System.in); +// String input = sc.nextLine(); // -// boolean isCapital = true; // 首字母是否大写 -// for (int i = left; i < input.length(); i++) { -// char c = input.charAt(i); -// if (c == ' ') { -// if (i > 0 && input.charAt(i - 1) == '.') { -// output.deleteCharAt(output.length() - 1); -// } -// // 跳过多余的空格 -// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') { -// i++; -// } -// if (input.charAt(i + 1) != '.') { -// output.append(' '); -// } -// } else if (c == '.') { -// // 句号后面要加一个空格 -// output.append(". "); -// isCapital = true; // 下一句话的首字母要大写 -// } else { -// if (isCapital) { -// // 首字母要大写 -// output.append(Character.toUpperCase(c)); -// isCapital = false; -// } else { -// output.append(c); -// } -// } -// } +// new testAnt().test(input); +//// StringBuilder output = new StringBuilder(); +//// int left = 0; +//// +//// //去除前面的 +//// while (left < input.length() && input.charAt(left) == ' ') { +//// left++; +//// } +//// +//// boolean isCapital = true; // 首字母是否大写 +//// for (int i = left; i < input.length(); i++) { +//// char c = input.charAt(i); +//// if (c == ' ') { +//// if (i > 0 && input.charAt(i - 1) == '.') { +//// output.deleteCharAt(output.length() - 1); +//// } +//// // 跳过多余的空格 +//// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') { +//// i++; +//// } +//// if (input.charAt(i + 1) != '.') { +//// output.append(' '); +//// } +//// } else if (c == '.') { +//// // 句号后面要加一个空格 +//// output.append(". "); +//// isCapital = true; // 下一句话的首字母要大写 +//// } else { +//// if (isCapital) { +//// // 首字母要大写 +//// output.append(Character.toUpperCase(c)); +//// isCapital = false; +//// } else { +//// output.append(c); +//// } +//// } +//// } +//// +//// System.out.println(output.toString()); +// sc.close(); // -// System.out.println(output.toString()); - sc.close(); - - } +// } public void test(String str) { @@ -106,4 +107,68 @@ public class testAnt { } + + + + + +// public static void main(String[] args) { +// Scanner scanner = new Scanner(System.in); +// int k = scanner.nextInt(); +// int count = 0; +// for (int i = 0; i < 65536; i++) { +// String hex = String.format("%04x", i); // 将整数转换成长度为 4 的十六进制数 +// if (isGoodHex(hex)) { +// count++; +// if (count == k) { +// System.out.println(hex); +// break; +// } +// } +// } +// } +// +// public static boolean isGoodHex(String hex) { +// Set digits = new HashSet<>(); +// for (char c : hex.toCharArray()) { +// digits.add(c); +// } +// return digits.size() == 4; +// } + + + public static void main(String[] args) { + String s = "????(?"; // 待匹配的字符串 + int left = 0, right = 0, count = 0; // 分别记录左括号、右括号和合法的括号对的数量 + Stack stack = new Stack<>(); // 栈,用于记录左括号和 '?' 的下标 + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '(' || c == '?') { + stack.push(i); + if (c == '(') { + left++; + } + } else { + if (stack.isEmpty()) { + continue; + } + stack.pop(); + if (c == ')') { + right++; + } + count++; + } + } + while (!stack.isEmpty()) { // 处理剩余的左括号或 '?' + int index = stack.pop(); + if (s.charAt(index) == '(') { + left--; + } else { + right--; + } + } + count += Math.min(left, right); // '?' 可以代替左括号或右括号,因此左右括号数量较小的值为合法的括号对数量 + System.out.println(count); + } + }