题目一
牛牛有一个括号字符串s,现在需要在其中任意位置尽量少地添加括号,将其转化 为一个完整的括号字符串。请问牛牛至少需要添加多少个括号。
代码
public static int minAddToMakeValid(String s) {
int ans = 0;
int count = 0;
for (int i = 0; i < s.length(); i++){
if (s.charAt(i) == '('){
count++;
}else {//为)括号
if (count == 0){
ans++;
}else {
count--;
}
}
}
retur n ans + count;
}
题目二
给定一个数组arr,求差值为k的去重数字对。 例如:[1,3,0,5] k = 2 则有(1,3)、(3,5)
代码
public static List<List<Integer>> allPair (int[] arr, int k) {
HashSet<Integer> set = new HashSet<>();
for (int i = 0; i < arr.length; i++){
set.add(arr[i]);
}
List<List<Integer>> res = new ArrayList<>();
for (Integer cur : set){
if (set.contains(cur + k)){
//Arrays.asList的作用是将数组转化为list
res.add(Arrays.asList(cur, cur + k));
}
}
return res;
}
public static void main(String[] args) {
int[] arr = new int[]{1,5,4,8,7,4,3,2,9};
System.out.println(allPair(arr, 4));
}
题目三
给一个包含n个整数元素的集合a,一个包含m个整数元素的集合b。
定义magic操作为,从一个集合中取出一个元素,放到另一个集合里,且操作过后每个集合的平均值都大大于于操作前。
注意以下两点:
1)不可以把一个集合的元素取空,这样就没有平均值了
2)值为x的元素从集合b取出放入集合a,但集合a中已经有值为x的元素,则a的平均值不变(因为集合元素不会重复),b的平均值可能会改变(因为x被取出了)
问最多可以进行多少次magic操作?
代码
public static int maxOps(int[] arr1, int[] arr2){
double sum1 = 0;
//记录arr1数组的全部和
for (int i= 0; i < arr1.length; i++){
sum1 += (double) arr1[i];
}
double sum2 = 0;
//记录arr2数组的全部和
for (int i= 0; i < arr2.length; i++){
sum2 += (double) arr2[i];
}
//如果两个的平均值相同,则不论什么操作,都没办法达到题目的要求
if (avg(sum1, arr1.length) == avg(sum2, arr2.length)){
return 0;
}
//平均值不相等
int[] arrMore = null;
int[] arrLess = null;
double sumMore = 0;
double sumLess = 0;
//重定位平均值大的集合和平均值小的集合,因为移动的时候,只可以从平均值大的集合移动到平均值小的集合
if (avg(sum1, arr1.length) > avg(sum2, arr2.length)){
arrMore = arr1;
sumMore = sum1;
arrLess = arr2;
sumLess = sum2;
}else {
arrMore = arr2;
sumMore = sum2;
arrLess = arr1;
sumLess = sum1;
}
//先将较大的排序是为了方便选择,因为元素从平均值大的集合移到平均值小的集合中,先移符合条件的最小的数,
//这样可以使大集合的平均值升最大,小集合升最慢,就可以找到原来不满足而现在满足的数了,增加了
//移动的数量
Arrays.sort(arrMore);
HashSet<Integer> setless = new HashSet<>();
//较小的集合需要用哈希表登记一下,因为我们为了保证移到小集合中的数据在小集合中没有
for (int num : arrLess){
setless.add(num);
}
int moreSize = arrMore.length;//平均值大的集合还剩几个数
int lessSize = arrLess.length;//平均值小的集合还剩几个数
int ops = 0;//操作了多少次
for (int i = 0; i < arrMore.length; i++){//从小到大依次选择平均值大的集合中的数
double cur = (double) arrMore[i];
if (cur < avg(sumMore, moreSize) && cur > avg(sumLess, lessSize)
&& !setless.contains(arrMore[i])){
sumMore -= cur;
moreSize--;
sumLess += cur;
lessSize++;
setless.add(arrMore[i]);
ops++;
}
}
return ops;
}
//算出平均值
public static double avg(double sum, int size){
return sum / (double) (size);
}
题目四
找到最长的有效括号子串
例如:())[()(())()]))(()) 最长即为8
代码
对于这种必须连续的子串或者子数组的问题,你就求每个位置结尾的情况下答案是多少。
dp[i]表示子串如果必须以i位置字符结尾,最长的长度是多大。如果遇到左括号结尾,直接填0;
public static int maxLength(String s){
if (s == null || s.equals("")){
return 0;
}
char[] str = s.toCharArray();
int[] dp = new int[str.length];
int pre = 0;
int res = 0;
for (int i = 1; i < str.length; i++){
//只考虑右括号就可以,因为左括号使用默认值0;
if (str[i] == ')'){
//看这个位置是不是左括号
pre = i - dp[i - 1] - 1;
//如果这个位置不越界并且第左括号
if (pre >= 0 && str[pre] == '('){
//如果是左括号至少+2,如果这个位置的前一个位置存在,就接上这个位置的值
dp[i] = dp[i - 1] + 2 + (pre > 0 ? dp[pre - 1] : 0);
}
}
}
return res;
}
题目五
请编写一个程序,对一个栈里的整型数据,按升序进行排序(即排序前,栈里 的数据是无序的,排序后最大元素位于栈顶),要求最多只能使用一个额外的 栈存放临时数据,但不得将元素复制到别的数据结构中。
代码
建立一个辅助栈,这个栈要实现从小到大放数。所以在输出到原stack栈中。
- 辅助栈进入了一个数
- 新进的数如果比它小,直接进入
- 新进的数如果比它大,辅助栈就依次弹出到可以放进去这个数,弹出的这个数放到原stack中
public static void sortStackByStack(Stack<Integer> stack){
Stack<Integer> help = new Stack<>();
while (!stack.isEmpty()){
int cur = stack.pop();
while(!help.isEmpty() && help.peek() < cur){
stack.push(help.pop());
}
help.push(cur);
}
while(!help.isEmpty()){
stack.push(help.pop());
}
}
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
stack.push(3);
stack.push(4);
stack.push(1);
stack.push(6);
stack.push(7);
stack.push(5);
sortStackByStack(stack);
while(!stack.isEmpty()){
System.out.println(stack.pop());// 7 6 5 4 3 1
}
}
题目六
将给定的数转换为字符串,原则如下:1对应 a,2对应b,…..26对应z,例如12258 可以转换为"abbeh", "aveh", "abyh", "lbeh" and "lyh",个数为5,编写一个函 数,给出可以转换的不同字符串的个数。
代码
动态规划,dp[i]表示包括它自己从i ~ length - 1的数转化成字符串可以有多少种。
public static int dpWays(int num){
if (num < 1){
return 0;
}
char[] str = String.valueOf(num).toCharArray();
int N = str.length;
int[] dp = new int[N + 1];
dp[N] = 1;//什么也没有算一种
//如果包含开头的是0,则一定为0.没法转换
dp[N - 1] = str[N - 1] == '0' ? 0 : 1;
for (int i = N - 2; i >= 0; i--){
if (str[i] == '0'){
dp[i] = 0;
}else {
//开头不为0,分成两种情况,当前单独算一个+当前和之后两个算在一起
dp[i] = dp[i + 1] + (((str[i] - '0') * 10 + str[i + 1] - '0') < 27 ? dp[i + 2] : 0);
}
}
return dp[0];
}
题目七
二叉树每个结点都有一个int型权值,给定一棵二叉树,要求计算出从根结点到 叶结点的所有路径中,权值和最大的值为多少。
代码
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int val){
value = val;
}
}
public static int maxSumRecursive(Node head){
return process(head, 0);
}
public static int process(Node x, int pre) {
if (x == null){
return Integer.MIN_VALUE;
}
if (x.left == null && x.right == null){
return pre + x.value;
}
int leftMax = process(x.left, pre + x.value);
int rightMax = process(x.right, pre + x.value);
return Math.max(leftMax, rightMax);
public static int maxSumUnrecursive(Node head) {
int max = 0;
HashMap<Node, Integer> sumMap = new HashMap<>();
if (head != null) {
Stack<Node> stack = new Stack<Node>();
stack.add(head);
sumMap.put(head, head.value);
while (!stack.isEmpty()) {
head = stack.pop();
if (head.left == null && head.right == null) {
max = Math.max(max, sumMap.get(head));
}
if (head.right != null) {
sumMap.put(head.right, sumMap.get(head) + head.right.value);
stack.push(head.right);
}
if (head.left != null) {
sumMap.put(head.left, sumMap.get(head) + head.left.value);
stack.push(head.left);
}
}
}
return max;
}