今天更一波最近刷的题目

如题,很久不写笔记了。
最近每天都坚持刷了一些大厂的题目。
没有什么突破性的进步,至少巩固了一些算法基础。

直接看题目。

题目描述
字符串旋转:
给定两字符串A和B,如果能将A从中间某个位置分割为左右两部分字符串(都不为空串),并将左边的字符串移动到右边字符串后面组成新的字符串可以变为字符串B时返回true。
例如:如果A=‘youzan’,B=‘zanyou’,A按‘you’‘zan’切割换位后得到‘zanyou’和B相同返回true。
输入描述:
2个不为空的字符串(说明:输入一个字符串以英文分号";"分割为2个字符串)
例如:youzan;zanyou 即为A=‘youzan’,B=‘zanyou’
输出描述:
输出true或false(表示是否能按要求匹配两个字符串)
示例1
输入
youzan;zanyou
输出
true
示例2
输入
youzan;zyouan
输出
false

这题没什么技术含量。这是一道有赞的题目。
直接暴力AC
以下为我的ac答案,可能有些暴力…
不够优雅。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        String[] s = str.split(";");
        String a = s[0];
        String b = s[1];
        System.out.println(solution(a, b));
    }

    public static boolean solution(String a, String b) {
        int index = b.length();
        while(index >= 0) {
            if(a.indexOf(b.substring(0, index)) != -1) break;
            index -= 1;
        }
        if(index == 0) return false;
        String t = "";
        t += b.substring(index, b.length());
        t += b.substring(0, index);

        //System.out.println(t);
        if(t.equals(a)) return true;
        return false;
    }
}

接着看第二题
给定一个非空的整数数组,从数组第一个元素(下标为0的元素)开始遍历进行移动,下一次向后或向前移动 该元素的值 的位数(值为正数向后移动,值为负数向前移动,值为零不移动),依次类推进行移动,若某次移动数组出现越界,则说明数组可以跳出,返回true;不能跳出则返回false;(加分项:也可考虑不增加使用其他集合数组辅助完成算法)
例1:
输入数组a[5] = [1,2,3,2,5];从第一个元素开始a[0]=1,下次向后移动1位到第二个元素a[1]=2,再次向后移动2位到第四个元素a[3],因为下次向后移动2位(a[3]=2)后,向后数组越界,即跳出数组,输出true;
例2:
输入数组a[2] = [1,-3];从第一个元素开始a[0]=1,下次移动1位到第二个元素a[1]=-3,再次向前移动3位后,向前数组越界,即跳出数组,输出true;
输入描述:
一个非空的整数数组(至少有一个元素,可正可负)
输出描述:
按规则移动后是否能跳出数组
示例1
输入
[1]
输出
true
示例2
输入
[2,1,3,5]
输出
true
示例3
输入
[2,1,-3]
输出
true
示例4
输入
[1,1,1,2,-1,1,-3]
输出
false

这题也是有赞的,有人用数学解法,好吧,我也没看,我用的是万能的递归。
暴力解了一下过了,于是设了一个数组加了优化。至少test的测试用例是全过了。
有兴趣看递归的注意一下我的index,因为我从0开始所以会耽误一次index,这个index要+1, 如果卡的不好是过不了的。

直接发解法了。

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        String t = str.substring(1, str.length() - 1);
        String[] s = t.split(",");
        int[] a = new int[s.length];
        visited = new boolean[a.length];
        for(int i = 0; i < a.length; i ++) {
            a[i] = Integer.valueOf(s[i]);
        }

        System.out.println(dfs(a, 0, 0, 0));
    }
    public static boolean[] visited;
    public static boolean dfs(int[] a, int pos, int index, int jump) {
        if(index > a.length + 1 && pos < a.length && pos >= 0) return false;
        if(pos < 0 || pos >= a.length) return true;
        boolean flag;
        if(pos + jump < a.length && pos + jump >= 0) {
            flag = dfs(a, pos + jump, index + 1, a[pos + jump]);
            visited[pos] = flag;
            return flag;
        }
        return true;
    }
}

给定一个数组A[n], 定义数组的众数 ( Majority Element) 为数组中出现次数超过 n/2 次的元素, 假设数组A[n]非空且一定存在众数, 请设计算法找到该众数并输出.
输入描述:
一个非空且一定存在众数的整数数组,如: [1,2,2]
输出描述:
输出打印该众数,如: 2
示例1
输入
[1,2,2]
输出
2
示例2
输入
[3,1,-2,3,1,3,3]
输出
3

众数问题,可以用hashmap,然后用一个getOrdefault函数更新key对应的value值。但是这样就用了o(n)的空间复杂度。
所以考虑不耗空间的解法。
就是将第一个数设为众数,开始计数。如果碰见一样的则计数+1,不一样的则-1,如果计数到了0,它就不可能为众数。则更新众数。最后得到的一定是众数了。前提是题目给的一定存在众数。

题目描述
给定一个无序的整型数组A[n],数组大小大于等于3,允许有值相同的元素;请设计算法找到该数组排序后第三大的元素值并输出.
输入描述:
一个非空的整数数组(至少有3个元素,可正可负)
输出描述:
第三大的元素值
示例1
输入
[1,2,3,4,5]
输出
3
示例2
输入
[1,1,2,2,3]
输出
2
示例3
输入
[6,5,4,4,1,2]
输出
4

一个经典题,面试中会考在十亿个数找到前一千个最大值是多少?
这个问题听起来就很伤,毕竟数字太大。
这里考虑用heap这个数据结构。
我总结了,求最大就用最小堆,最小则用最大堆,这样一说大家应该可以理解,如果求前3个最大值,那用容量为3的最小堆,先放入3个,如果堆顶的值小于之后的数,就把堆顶poll掉,然后放入那个比他大的数,堆的内部会自动调整。在上面的例子中,如果用排序算法,如果用归并,则消耗了o(十亿)的空间复杂度,这就太可怕了,如果是选择,又要承受o(n^2)的空间复杂度。最优的排序也不过是用o(十亿log(十亿))这样的时空复杂度是无法接受的。
那么用堆,则仅仅用了o(1000)的空间复杂度,而时间复杂度为(十亿
log(一千))。遍历一遍, 堆的调整复杂度大概为log(一千)。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        PriorityQueue<Integer> heap = new PriorityQueue<Integer>(3, new Comparator<Integer>(){
            public int compare(Integer i1, Integer i2) {
                return i1 - i2;
            }
        });

        Scanner in = new Scanner(System.in);

        String str = in.nextLine();
        String s = str.substring(1, str.length() - 1);
        String[] t = s.split(",");
        int[] a = new int[t.length];
        for(int i = 0; i < a.length; i ++)
            a[i] = Integer.valueOf(t[i]);

        for(int i = 0; i < 3; i ++) {
            heap.offer(a[i]);
        }
        for(int i = 3; i < a.length; i ++) {
            if(a[i] > heap.peek()) {
                heap.poll();
                heap.offer(a[i]);
            }
        }
        
        System.out.print(heap.poll());
    }
}

然后看下一题,我没有AC,因为输出的格式…
但是我可以把我得思想分享出来,应该是对的,有没有AC就不重要了。

**某天猿辅导 HR 组织大家去漂流,早上,参加团建的同学都到齐了,并且按到达公司的先后顺序排好队了。 由于员工太多,一个大巴车坐不下,需要分多个车,车是足够的,但所有人需要按一定顺序上车,按如下规则安排上车的顺序:
假设大巴车容量为 m,从队首开始,每 m 个人分成一个小组,每个小组坐一辆车。同时只有一个车打开车门供员工上车。 小组之间按从队尾到队首顺序依次上车,同一小组内先到的同学先上,求所有人上车的顺序。
例如: 员工数 8, 车容量 3, 员工到达顺序为 1 2 3 4 5 6 7 8, 3个人一个小组,分三个小组, 小组一: 1, 2, 3, 小组二: 4, 5, 6,小组三: 7,8。 小组上车顺序为: 小组三,小组二,小组一 。 所有员工上车顺序为 7 8 4 5 6 1 2 3

#include
int main() {
int memberCount, carCount;
std::cin >> memberCount;
std::cin >> carCount;

int* members = new int[memberCount];
for (int i = 0; i < memberCount; i++) {
    std::cin >> members[i];
}

// TODO: 按规则调整顺序
while(true)
{
    // TODO: 输出,注意有空格隔开
    std::cout << orders[i];
}

delete[] members;
delete[] orders;

}
输入描述:
第一行: 员工数和大巴容量
第二行: 所有员工工号(按到达顺序)
输出描述:
员工编号
示例1
输入
复制
5 3
1 3 5 2 4
输出
复制
2 4 1 3 5
笔记
收藏
纠错
**

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m = in.nextInt(); // 员工数
        int n = in.nextInt(); //大巴容量
        int[] a = new int[m];
        for(int i = 0; i < m; i ++) {
            a[i] = in.nextInt();
        }
        
        List<List<Integer>> list = new ArrayList<>();
        int index = 0;
        while(index < a.length) {
            List<Integer> t = new ArrayList<>();
            for(int i = index; i < index + n && i < a.length; i ++) {
                t.add(a[i]);
            }
            list.add(t);
            index += n;
        }
        
        Stack<List<Integer>> stack = new Stack<>();
        for(List<Integer> i : list) {
            stack.push(i);
        }
        for(List<Integer> i : stack) {
            System.out.print(stack.pop() + " ");
        }
    }
}

用了栈的思想。
一看就明白。

题目描述
注意:本题允许使用C/C++/Java/python进行解答,其他编程语言提交均视作无效处理。
小W有一个电子时钟用于显示时间,显示的格式为HH:MM:SS,HH,MM,SS分别表示时,分,秒。其中时的范围为[‘00’,‘01’…‘23’],分的范围为[‘00’,‘01’…‘59’],秒的范围为[‘00’,‘01’…‘59’]。

但是有一天小W发现钟表似乎坏了,显示了一个不可能存在的时间“98:23:00”,小W希望改变最少的数字,使得电子时钟显示的时间为一个真实存在的时间,譬如“98:23:00”通过修改第一个’9’为’1’,即可成为一个真实存在的时间“18:23:00”。修改的方法可能有很多,小W想知道,在满足改变最少的数字的前提下,符合条件的字典序最小的时间是多少。其中字典序比较为用“HHMMSS”的6位字符串进行比较。
输入描述:
每个输入数据包含多个测试点。每个测试点后有一个空行。 第一行为测试点的个数T(T<=100)。 每个测试点包含1行,为一个字符串”HH:MM:SS”,表示钟表显示的时间。
输出描述:
对于每个测试点,输出一行。如果钟表显示的时间为真实存在的时间,则不做改动输出该时间,否则输出一个新的”HH:MM:SS”,表示修改最少的数字情况下,字典序最小的真实存在的时间。
示例1
输入
复制
2
19:90:23
23:59:59
输出
复制
19:00:23
23:59:59

这一题比较弟弟。
贪心的思想,一遍AC
将高位改成0即可。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        String[] test = new String[n];
        int index = 0;
        while(n -- > 0) {
            String str = in.next();
            test[index ++] = str;

        }
        for(String i : test) {
            System.out.println(solution(i));
        }
    }
    
    public static String solution(String str) {
        String[] t = str.split(":");
        if(Integer.valueOf(t[0]) < 0 || Integer.valueOf(t[0]) > 23) {
            t[0] = "0" + t[0].charAt(1);
        }
        if(Integer.valueOf(t[1]) < 0 || Integer.valueOf(t[1]) > 59) {
            t[1] = "0" + t[1].charAt(1);
        }
        if(Integer.valueOf(t[2]) < 0 || Integer.valueOf(t[2]) > 59) {
            t[2] = "0" + t[2].charAt(1);
        }
        String ans = t[0] + ":" + t[1] + ":" + t[2];
        return ans;
    }
}

我们部门要排队唱歌,大家乱哄哄的挤在一起,现在需要按从低到高的顺序拍成一列,但每次只能交换相邻的两位,请问最少要交换多少次
输入描述:
第一行是N(N<50000),表示有N个人
然后每一行是人的身高Hi(Hi<2000000,不要怀疑,我们以微米计数),持续N行,表示现在排列的队伍
输出描述:
输出一个数,代表交换次数。
示例1
输入
复制
6
3
1
2
5
6
4
输出
复制
4

这题有难度。
一开始看,如果大一排序学的好的人,肯定直接冒泡,就比如我。
(狗头
哈哈,冒泡就是相邻互换的思想。
于是撸了一发冒泡。

import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] h = new int[n];
        for(int i = 0; i < n; i ++) {
            h[i] = in.nextInt();
        }
        int count = 0;
        for(int i = 0; i < n - 1; i ++) {
            for(int j = 0; j < n - i - 1; j ++) {
                if(h[j] > h[j + 1]) {
                    int t = h[j];
                    h[j] = h[j + 1];
                    h[j + 1] = t;
                    count += 1;
                }
            }
        }
        System.out.println(count);
    }
}

超时了,不过过了80%。要是真的笔试,那也能拿到%80的分了,所以如果不会其他解法,这么写也不亏了。

那么更优解是什么呢?是另一种排序,归并排序。
归并排序是基于递归的思想,这里用归并算逆序数,思路还是很妙的!
因为归并分到最后,合并的是一个个有序的小数组!这样即可
那比如 5678 3456 合并这两个小数组,这样是可以计算逆序数的!
比如3,那么5678 都算,4 5678都算,5 678 算 6 78 算。
中间是有一个mid作为划分的,那么计数的count, 就等于 count += a[p1] <= a[p2] ? 0 : mid - p1 + 1;
p1, p2分别代表从5开始的指针,和从mid开始的指针。向右移动。

那么就上代码了,这题我一开始也并不会。
其实基本就相当于一个归并排序。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] h = new int[n];
        for(int i = 0; i < n; i ++) {
            h[i] = in.nextInt();
        }
        merge(h, 0, h.length - 1);
        System.out.println(count);
    }
    public static int count = 0;
    public static void merge(int[] a, int l, int r) {
        if(l == r) return ;
        int mid = (r - l) / 2 + l;
        merge(a, l, mid);
        merge(a, mid + 1, r);
        int p1 = l;
        int p2 = mid + 1;
        int index = 0;
        int[] t = new int[r - l + 1];
        while(p1 <= mid && p2 <= r) {
            count += a[p1] <= a[p2] ? 0 : mid - p1 + 1;
            t[index ++] = a[p1] <= a[p2] ? a[p1 ++] : a[p2 ++];
        }
        while(p1 <= mid) {
            t[index ++] = a[p1 ++];
        }
        while(p2 <= r) {
            t[index ++] = a[p2 ++];
        }
        
        for(int i = 0; i < t.length; i ++) {
            a[l + i] = t[i];
        }
    }
}

题目描述
我们有很多区域,每个区域都是从a到b的闭区间,现在我们要从每个区间中挑选至少2个数,那么最少挑选多少个?
输入描述:
第一行是N(N<10000),表示有N个区间,之间可以重复
然后每一行是ai,bi,持续N行,表示现在区间。均小于100000
输出描述:
输出一个数,代表最少选取数量。
示例1
输入
复制
4
4 7
2 4
0 2
3 6
输出
复制
4

这题属于区间求点的问题吧。不过这是两个点,不过为难了我差不多两个小时才AC!其实不难。。
只是贪心策略我考虑错了
我们思考一下

3—— 6
1 ————9
这两个线段,按照题意,则用两个点就可以,那么你会取哪两个?
我傻傻的用3和6这两个点,因为我觉得,范围越大对下面的线段越有利!
这是不对的,正确的贪心策略是用5 6
为什么呢
3——6
1——————9
4——6
这样的话,那么5 ,6则概括了三条线段,而3 6 就弟弟了。
而且就算是2 ——6, 那3 6可以的, 5,6一样可以!

所以我就这样修修改改搞了差不多两个小时…太弟弟了。
首先要按照右边的点排序。如果囊括了两边,则不需要加点
如果囊括了右点则+1,顺便更新两个点。如果没有重叠,则加2
贪心策略如上所说。

import java.util.*;

public class Main {
    public static class seg {
        public int a;
        public int b;
        public seg(int a, int b) {
            this.a = a;
            this.b = b;
        }
    }

    public static class segSort implements Comparator<seg> {
        public int compare(seg i1, seg i2) {
            return i1.b != i2.b ? i1.b - i2.b : i2.a - i1.a;
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        seg[] s = new seg[n];
        for(int i = 0; i < n; i ++) {
            int a = in.nextInt();
            int b = in.nextInt();
            s[i] = new seg(a, b);
        }
        Arrays.sort(s, new segSort());
        int p1 = s[0].b - 1;
        int p2 = s[0].b;

        int count = 2;
        for(int i = 1; i < n; i ++) {
            if(s[i].a <= p1 && s[i].b >= p2)
                continue;
            else if(s[i].a <= p2) {
                count += 1;
                p1 = s[i].b - 1;
                p2 = s[i].b;
            }
            else if(s[i].a > p2) {
                count += 2;
                p1 = s[i].b - 1;
                p2 = s[i].b;
            }
        }

        System.out.println(count);
    }
}

有一个X*Y的网格,小团要在此网格上从左上角到右下角,只能走格点且只能向右或向下走。请设计一个算法,计算小团有多少种走法。给定两个正整数int x,int y,请返回小团的走法数目。
输入描述:
输入包括一行,空格隔开的两个正整数x和y,取值范围[1,10]。
输出描述:
输出一行,表示走法的数目
示例1
输入
复制
3 2
输出
复制
10

弟弟题目,2分钟AC,大家都在用DP,那么我就偏偏用记忆化递归。
不比DP慢。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int x = in.nextInt();
        int y = in.nextInt();
        visited = new int[x + 1][y + 1];
        for(int i = 0; i <= x; i ++) {
            for(int j = 0; j <= y; j ++)
                visited[i][j] = -1;
        }
        System.out.println(dfs(0, 0, x + 1, y + 1));
    }
    public static int[][] visited; 
    public static int dfs(int x, int y, int row, int col) {
        if(x == row - 1 && y == col - 1) {
            return 1;
        }
        if(x >= row || y >= col) return 0;
        if(visited[x][y] != -1) return visited[x][y];
        int ans = dfs(x + 1, y, row, col) + dfs(x, y + 1, row, col);
        visited[x][y] = ans;
        return ans;
    }
}

题目描述
给定一个字符串,输出所有指定长度为n的子串,没有则输出-1
输入描述:
输入第一行一个字符串,如:“1234567890”
输入第二行一个数字是n,如5
输出描述:
输出所有长度为n的子串,如“12345”,“23456”,“34567”,“45678”,“56789”
示例1
输入
复制
123456789
5
输出
复制
12345 23456 34567 45678 56789

蘑菇街。这题就简单了。
有毒的是我自己的idea可以编出来的答案,他每次给我不通过,我也是醉了。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.next();
        int n = in.nextInt();
        if(n <= 0 || str.length() < n) System.out.println(-1);
        else {
            System.out.print(str.substring(0, n));
            for(int i = 1; i <= str.length() - n; i ++) {
            System.out.print(" " + str.substring(i, i + n));
            }
        }
        
    }
}

题目描述
请编写一段代码,实现两个单向有序链表的合并
输入描述:
第一行一个链表,如1 2 3 4 5
第二行一个链表,如2 3 4 5 6
输出描述:
输出:1 2 2 3 3 4 4 5 5 6
示例1
输入
复制
1 2 3 4 5
2 3 4 5 6
输出
复制
1 2 2 3 3 4 4 5 5 6

一样是蘑菇街,Leetcode原题。不同的只不过是你要从头自己撸ListNode.
同样的输入很烦人!
不过过程还是比较简单的。
不要忘记在合并的时候新链表的newList = newList.next,要持续往下走。我比较容易忘了这个。

import java.util.*;

public class Main {
    public static class ListNode {
        public int val;
        public ListNode next;
        public ListNode(int val) {
            this.val = val;
            this.next = null;
        }
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str1 = in.nextLine();
        String str2 = in.nextLine();
        String[] a = str1.split(" ");
        String[] b = str2.split(" ");

        int[] list1 = new int[a.length];
        int[] list2 = new int[b.length];


        for(int i = 0; i < a.length; i ++)
            list1[i] = Integer.valueOf(a[i]);
        for(int i = 0; i < b.length; i ++)
            list2[i] = Integer.valueOf(b[i]);

        ListNode heada = new ListNode(list1[0]);
        ListNode headb = new ListNode(list2[0]);
        ListNode x = heada;
        ListNode y = headb;
        for(int i = 1; i < a.length; i ++) {
            x.next = new ListNode(list1[i]);
            x = x.next;
        }
        for(int i = 1; i < b.length; i ++) {
            y.next = new ListNode(list2[i]);
            y = y.next;
        }

        ListNode cura = heada;
        ListNode curb = headb;
        ListNode newList = new ListNode(0);
        ListNode newlist = newList;
        while(cura != null && curb != null) {
            if(cura.val < curb.val) {
                newlist.next = cura;
                cura = cura.next;
            }
            else {
                newlist.next = curb;
                curb = curb.next;
            }
            newlist = newlist.next;
        }
        newlist.next = cura == null ? curb : cura;

        ListNode t = newList.next;

        while(t != null) {
            System.out.print(t.val + " ");
            t = t.next;
        }
    }
}

题目描述
括号配对问题
输入描述:
给定一个字符串S,请检查该字符串的括号是否配对,只含有"[", “]”, “(”, “)”
输出描述:
配对,返回true
不配对,返回false
示例1
输入
复制
abcd(])[efg
输出
复制
false

唯品会。

看到括号匹配一秒就该想到栈。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        Stack<Character> stack = new Stack<>();
        for(int i = 0; i < str.length(); i ++) {
            if(str.charAt(i) == '[') {
                stack.push(str.charAt(i));
            } else if(str.charAt(i) == '(') 
                stack.push(str.charAt(i));
            else if(str.charAt(i) == ']') {
                 if(!stack.isEmpty() && stack.peek() == '[')
                     stack.pop();
                else stack.push(str.charAt(i));
            }
            else if(str.charAt(i) == ')') {
                if(!stack.isEmpty() && stack.peek() == '(')
                    stack.pop();
                else stack.push(str.charAt(i));
            }
                
            else 
                continue;
        }
        System.out.println(stack.isEmpty());
    }
}

一遍AC,还记得是大一寒假第一次接触的题型,时间真快。

题目描述
小明在越南旅游,参加了当地的娱乐活动。小明运气很好,拿到了大奖, 到了最后的拿奖金环节。小明发现桌子上放着一列红包,每个红包上写着奖金数额。
现在主持人给要求小明在这一列红包之间“切”2刀,将这一列红包“切”成3组,并且第一组的奖金之和等于最后一组奖金和(允许任意一组的红包集合是空)。最终第一组红包的奖金之和就是小明能拿到的总奖金。小明想知道最多能拿到的奖金是多少,你能帮他算算吗。
举例解释:桌子上放了红包 1, 2, 3, 4, 7, 10。小明在“4,7”之间、“7,10” 之间各切一刀,将红包分成3组 [1, 2, 3, 4] [7] [10],其中第一组奖金之和=第三组奖金之和=10,所以小明可以拿到10越南盾。
输入描述:
第一行包含一个正整数n,(1<=n<= 200 000),表示有多少个红包。
第二行包含n个正整数d[i],表示每个红包包含的奖金数额。其中1<= d[i] <= 1000 000 000
输出描述:
小明可以拿到的总奖金
示例1
输入
复制
5
1 3 1 1 4
输出
复制
5
说明
[1,3,1] [ ] [1,4] ,其中第一组奖金和是5,等于第三组奖金和。所以小明可以拿到5越南盾
示例2
输入
复制
5
1 3 2 1 4
输出
复制
4
说明
[1,3] [2,1] [4],小明可以拿到4越南盾
示例3
输入
复制
3
4 1 2
输出
复制
0
说明
[ ] [4, 1, 2] [ ] ,小明没办法,为了保证第一组第三组相等,只能都分成空的。所以小明只能拿到0越南盾。

快手。怎么说呢,还是比较简单的。10分钟应该可以ac.
不解释了,直接看代码。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        long[] a = new long[n];
        for(int i = 0; i < n; i ++)
            a[i] = in.nextInt();
        long max = 0;
        int left = 0;
        int right = a.length - 1;
        long sumL = a[left];
        long sumR = a[right];
        while(left < right) {
            if(sumL == sumR) {
                max = Math.max(sumL, max);
                left += 1;
                right -= 1;
                sumL += a[left];
                sumR += a[right];
            }
            else if(sumL < sumR) {
                left += 1;
                sumL += a[left];
            }
            else {
                right -= 1;
                sumR += a[right];
            }
        }
        System.out.println(max);
    }
    
}

给满出二叉树,编写算法将其转化为求和树
什么是求和树:二叉树的求和树, 是一颗同样结构的二叉树,其树中的每个节点将包含原始树中的左子树和右子树的和。
二叉树:
10
/
-2 6
/ \ / \
8 -4 7 5
求和树:
20(4-2+12+6)
/
4(8-4) 12(7+5)
/ \ / \
0 0 0 0
二叉树给出前序和中序输入,求和树要求中序输出;
所有处理数据不会大于int;
输入描述:
2行整数,第1行表示二叉树的前序遍历,第2行表示二叉树的中序遍历,以空格分割
输出描述:
1行整数,表示求和树的中序遍历,以空格分割
示例1
输入
复制
10 -2 8 -4 6 7 5 8 -2 -4 10 7 6 5
输出
复制
0 4 0 20 0 12 0

这题很有意思,我没AC,过了80%。
这里求和 ,是可以在你的类里面放一个sumvalue记录以下子树的和的。

这样刚好还巧妙地优化了递归,实在是妙。
如此,递归的时间复杂度就是O(n)了。

import java.util.*;

public class Main {
    public static class TreeNode {
        public int val;
        public int sum;
        public TreeNode left;
        public TreeNode right;
        public TreeNode(int val) {
            this.val = val;
        }
    }
    public static TreeNode dfs(int[] pre, int preStart, int preEnd, int inStart) {
        if(preStart > preEnd) {
            return null;
        }
        TreeNode root = new TreeNode(pre[preStart]);
        int index = map.get(root.val);
        int leftTreeSize = index - inStart;
        root.left = dfs(pre, preStart + 1, preStart + leftTreeSize, inStart);
        root.right = dfs(pre, preStart + leftTreeSize + 1, preEnd, inStart + leftTreeSize + 1);
        return root;
    }

    public static void inOrder(TreeNode root) {
        if(root == null) return ;
        inOrder(root.left);
        System.out.print(root.sum + " ");
        inOrder(root.right);
    }

    public static void sumTree(TreeNode root) {
        if(root.left == null && root.right == null) {
            root.sum = 0;
        } else if(root.left == null) {
            sumTree(root.right);
            root.sum = root.right.sum + root.right.val;
        } else if(root.right == null) {
            sumTree(root.left);
            root.sum = root.left.sum + root.left.val;
        } else {
            sumTree(root.left);
            sumTree(root.right);
            root.sum = root.left.val + root.right.val + root.left.sum + root.right.sum;
        }
    }

    public static Map<Integer, Integer> map = new HashMap<Integer, Integer>();
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String Pre = sc.nextLine();
        String[] a = Pre.split(" ");
        int[] pre = new int[a.length];
        for(int i = 0; i < a.length; i ++) {
            pre[i] = Integer.parseInt(a[i]);
        }
        String In = sc.nextLine();
        String[] b = In.split(" ");
        int[] in = new int[b.length];
        for(int i = 0; i < a.length; i ++) {
            in[i] = Integer.parseInt(b[i]);
        }

        for(int i = 0; i < in.length; i ++) {
            map.put(in[i], i);
        }
        TreeNode tree = dfs(pre, 0, in.length - 1, 0);
        sumTree(tree);
        inOrder(tree);
    }
}

题目描述
前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。
由于太过兴奋,晚上月神做了一个奇怪的梦,月神梦见自己掉入了一个被施放了魔法的深渊,月神想要爬上此深渊。
已知深渊有N层台阶构成(1 <= N <= 1000),并且每次月神仅可往上爬2的整数次幂个台阶(1、2、4、…),请你编程告诉月神,月神有多少种方法爬出深渊
输入描述:
输入共有M行,(1<=M<=1000)
第一行输入一个数M表示有多少组测试数据,
接着有M行,每一行都输入一个N表示深渊的台阶数
输出描述:
输出可能的爬出深渊的方式
示例1
输入
复制
4
1
2
3
4
输出
复制
1
2
3
6
备注:
为了防止溢出,可将输出对10^9 + 3取模

快手的简单DP。和爬楼梯区别不大。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        while(n -- > 0) {
            int x = in.nextInt();
            System.out.println(dp(x));
        }
    }
    
    public static int dp(int x) {
        int[] dp = new int[x + 1];
        dp[0] = 1;
        for(int i = 1; i <= x; i ++) {
            for(int j = 0; j <= x; j ++) {
                if(i >= Math.pow(2, j)) {
                    dp[i] += dp[i - (int)Math.pow(2, j)];
                    dp[i] %= 1000000003;
                } else break;
            }
        }
     return dp[x] % 1000000003;
    }
}

题目描述
小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?
定义每一个长方形的长L和宽W都为正整数,并且1 <= W <= L <= INT_MAX, 袋子里面长方形的个数为N, 并且 1 <= N <= 1000000.
假如袋子里共有5个积木分别为 (2, 2), (2, 4), (3, 3), (2, 5), (4, 5), 则不难判断这些积木最多可以搭成4层, 因为(2, 2) < (2, 4) < (2, 5) < (4, 5)。
输入描述:
第一行为积木的总个数 N
之后一共有N行,分别对应于每一个积木的宽W和长L
输出描述:
输出总共可以搭的层数
示例1
输入
复制
5
2 2
2 4
3 3
2 5
4 5
输出
复制
4

先排序再DP,就是最长子序列。
dp用二分优化,这题真绝,普通DP还过不了,就是说O(n^2)过不了
必须得用O(n * logn)得复杂度。绝了
二分还很难,不容易想到,我琢磨了整整一个下午…实在是笨

import java.util.*;

public class Main {
    
    public static class wood {
        public int length;
        public int width;
        public wood(int length, int width) {
            this.length = length;
            this.width = width;
        }
    }
    
    public static class woodSort implements Comparator<wood> {
        public int compare(wood i1, wood i2) {
            return i1.width != i2.width ? i1.width - i2.width : i1.length - i2.length;
        }
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        wood[] t = new wood[n]; 
        for(int i = 0; i < n; i ++) {
            int x = in.nextInt();
            int y = in.nextInt();
            t[i] = new wood(x, y);
        }
        Arrays.sort(t, new woodSort());
        System.out.println(dp(t));
    }
    
    public static int dp(wood[] t) {
        wood[] dp = new wood[t.length];
        int res = 0;
        for(wood num : t) {
            int l = 0;
            int r = res;
            while(l < r) {
                int mid = (r - l) / 2 + l;
                if(num.length >= dp[mid].length) l = mid + 1;
                else r = mid;
            }
            dp[l] = num;
            if(r == res) res += 1;
        }
        return res;
    }
}

题目描述
通过键盘输入一串小写字母(a~z)组成的字符串。
请编写一个字符串归一化程序,统计字符串中相同字符出现的次数,并按字典序输出字符及其出现次数。
例如字符串"babcc"归一化后为"a1b2c2"
输入描述:
每个测试用例每行为一个字符串,以’\n’结尾,例如cccddecca
输出描述:
输出压缩后的字符串ac5d2e
示例1
输入
复制
dabcab
输出
复制
a2b2c1d1

快手简单题。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        String ans = "";
        int[] a = new int[26];
        Arrays.fill(a, 0);
        for(int i = 0; i < str.length(); i ++) {
            a[str.charAt(i) - 'a'] += 1;
        }
        for(int i = 0; i < 26; i ++) {
            if(a[i] == 0) continue;
            else {
                ans += (char) (i + 'a');
                ans += a[i];
            }
        }
        System.out.println(ans);
    }
   
}

题目描述
小明有26种游戏海报,用小写字母"a"到"z"表示。小明会把游戏海报装订成册(可能有重复的海报),册子可以用一个字符串来表示,每个字符就表示对应的海报,例如abcdea。小明现在想做一些“特别版”,然后卖掉。特别版就是会从所有海报(26种)中随机选一张,加入到册子的任意一个位置。
那现在小明手里已经有一种海报册子,再插入一张新的海报后,他一共可以组成多少不同的海报册子呢?
输入描述:
海报册子的字符串表示,1 <= 字符串长度<= 20
输出描述:
一个整数,表示可以组成的不同的海报册子种类数
示例1
输入
复制
a
输出
复制
51
说明
我们可以组成 ‘ab’,‘ac’,…,‘az’,‘ba’,‘ca’,…,‘za’ 还有 ‘aa’, 一共 51 种不同的海报册子。

快手的,这题看上去吓人其实不然,列几个,找个规律就AC

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        int len = str.length() + 1;
        System.out.println(len * 26 - len + 1);
    }
}

题目描述
请实现一个函数,功能为合并两个升序数组为一个升序数组
点击页面左下角“例2”,了解如何实现输入输出
输入描述:
输入有多个测试用例,每个测试用例有1-2行,每行都是以英文逗号分隔从小到大排列的数字
输出描述:
输出一行以英文逗号分隔从小到大排列的数组
示例1
输入
复制
1,5,7,9
2,3,4,6,8,10
输出
复制
1,2,3,4,5,6,7,8,9,10
备注:
不允许使用原生的 sort、concat 等函数

import java.util.*;


public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        List<Integer> arr = new ArrayList<>();

        String str1 = in.nextLine();
        String str2 = in.nextLine();

        String[] t1 = str1.split(",");
        String[] t2 = str2.split(",");
        int[] a = new int[t1.length];
        int[] b = new int[t2.length];

        for(int i = 0; i < t1.length; i ++) {
            a[i] = Integer.valueOf(t1[i]);
        }
        for(int i = 0; i < t2.length; i ++) {
            b[i] = Integer.valueOf(t2[i]);
        }

        int left = 0, right = 0;
        while(left <= a.length && right <= b.length) {
            if(left == a.length) {
                for(int i = right; i < b.length; i ++)
                    arr.add(b[i]);
                break;
            }
            else if(right == b.length) {
                for(int i = left; i < a.length; i ++)
                    arr.add(a[i]);
                break;
            }
            else {
                if(a[left] < b[right]) {
                    arr.add(a[left]);
                    left += 1;
                } else if(a[left] > b[right]) {
                    arr.add(b[right]);
                    right += 1;
                } else {
                    arr.add(a[left]);
                    arr.add(b[right]);
                    left += 1;
                    right += 1;
                }
            }
        }
        Integer[] ans = new Integer[arr.size()];
        ans = (Integer[]) arr.toArray(ans);
        for(int i = 0; i < ans.length - 1; i ++) {
            System.out.print(ans[i] + ",");
        }
       System.out.print(ans[ans.length - 1]);
    }
}

令人无语的输入…
简单题,会归并的一定会。

题目描述
我们定义字符串包含关系:字符串A=abc,字符串B=ab,字符串C=ac,则说A包含B,A和C没有包含关系。
输入描述:
两个字符串,判断这个两个字符串是否具有包含关系,测试数据有多组,请用循环读入。
输出描述:
如果包含输出1,否则输出0.
示例1
输入
复制
abc ab
输出
复制
1

indexOf函数一键秒杀。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while(in.hasNext()) {
            String str = in.nextLine();
        String[] s = str.split(" ");
        int len1 = s[0].length();
        int len2 = s[1].length();

        if(len1 > len2) {
            if(s[0].indexOf(s[1]) == -1) {
                System.out.println(0);
            }
            else System.out.println(1);
        }
        else {
            if(s[1].indexOf(s[0]) == -1) {
                System.out.println(0);
            }
            else System.out.println(1);
        }

        }
        
    }
}

有重量分别为3,5,7公斤的三种货物,和一个载重量为X公斤的箱子(不考虑体积等其它因素,只计算重量)
需要向箱子内装满X公斤的货物,要求使用的货物个数尽可能少(三种货物数量无限)
输入描述:
输入箱子载重量X(1 <= X <= 10000),一个整数。
输出描述:
如果无法装满,输出 -1。
如果可以装满,输出使用货物的总个数。
示例1
输入
复制
4
输出
复制
-1
说明
无法装满
示例2
输入
复制
8
输出
复制
2
说明
使用1个5公斤,1个3公斤货物

赤裸裸的硬币DP题。都不需要讲解。不可能不懂。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int x = in.nextInt();
        int[] dp = new int[x + 1];
        for(int i = 0; i <= x; i ++)
            dp[i] = x + 1;
        dp[0] = 0;
        int[] a = {3, 5, 7};
        for(int i = 1; i <= x; i ++) {
            for(int j = 0; j < 3; j ++) {
                if(i >= a[j]) {
                    dp[i] = Math.min(dp[i], dp[i - a[j]] + 1);
                }
            }
        }
        int ans = dp[x] == x + 1 ? -1 : dp[x];
        System.out.println(ans);
    }
}

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
(“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。)
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
可用C++,Java,C#实现相关代码逻辑
输入描述:
输入一个字符串S 例如“aabcb”(1 <= |S| <= 50), |S|表示字符串S的长度。
输出描述:
符合条件的字符串有"a”,“a”,“aa”,“b”,“c”,“b”,“bcb”
所以答案:7
示例1
输入
复制
aabcb
输出
复制
7

回文要么马拉车要么DP,而马拉车算法太难我不会,所以只能用DP…

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        boolean[][] dp = new boolean[str.length()][str.length()];
        int ans = 0;
        for(int i = str.length() - 1; i >= 0; i --) {
            for(int j = i; j < str.length(); j ++) {
                dp[i][j] = ((str.charAt(i) == str.charAt(j)) && (j - i <= 2 || dp[i + 1][j - 1]));
                if(dp[i][j]) ans += 1;
            }
        }
        System.out.println(ans);
    }
}

考虑好dp含义是比较容易的。
吐槽一下马拉车有点难啊…
题目描述
一个非空整数数组,选择其中的两个位置,使得两个位置之间的数和最大。
如果最大的和为正数,则输出这个数;如果最大的和为负数或0,则输出0
输入描述:
3,-5,7,-2,8
输出描述:
13
示例1
输入
复制
-6,-9,-10
输出
复制
0

很明显的dp了。dp入门题。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        String[] t = str.split(",");
        int[] a = new int[t.length];
        for(int i = 0; i < a.length; i ++) {
            a[i] = Integer.valueOf(t[i]);
        }
        if(a.length == 1) System.out.println(a[0] >= 0 ? a[0] : 0); 
        else {
            int[] dp = new int[a.length];
        for(int i = 0; i < dp.length; i ++)
            dp[i] = Integer.MIN_VALUE;
        dp[0] = a[0];
        int max = 0;
        for(int i = 1; i < a.length; i ++) {
            dp[i] = Math.max(dp[i - 1] + a[i], a[i]);
            max = Math.max(max, dp[i]);
        }
        System.out.println(max);
        }
        
    }
}

题目描述
输入年、月、日,计算该天是本年的第几天。
输入:
包括三个整数年(1<=Y<=3000)、月(1<=M<=12)、日(1<=D<=31)。
输出:
输入可能有多组测试数据,对于每一组测试数据,
输出一个整数,代表Input中的年、月、日对应本年的第几天。
输入描述:
输入:1990 9 20
输出描述:
输入:263
示例1
输入
复制
2000 5 1
输出
复制
122
备注:
注意闰年的判定方式

别傻不拉几的用switch case了,累不累呀,不过你要说要用一个大小为int 12的数组,我也没话说,哈哈。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int y = in.nextInt();
        int m = in.nextInt();
        int d = in.nextInt();
        int[] month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        if((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
            month[1] = 29;
        int sum = 0;
        if(m == 1) sum = d;
        else {
            for(int i = 0; i < m - 1; i ++) {
            sum += month[i];
        }
        sum += d;
        }
        
        System.out.println(sum);
    }
}

题目描述
有一个无限长的数字序列1,2,2,3,3,3,4,4,4,4,5,5,5,5,5。。。(数字序列从1开始递增,且数字k在该序列中正好出现k次),求第n项是多少
输入描述:
输入为一个整数n
输出描述:
输出一个整数,即第n项的值
示例1
输入
复制
4
输出
复制
3
备注:
如:输入为3,有序数列第3项的值为2,则输出为2

等差数列,稍微想一想,就会很快解决掉。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int ans = n;
        for(int i = 1; i < n; i ++) {
            if(i + i * (i - 1) / 2 >= n) {
                ans = i;
                break;
            }
        }
        System.out.println(ans);
    }
}

题目描述
你需要爬上一个N层的楼梯,在爬楼梯过程中, 每阶楼梯需花费非负代价,第i阶楼梯花费代价表示为cost[i], 一旦你付出了代价,你可以在该阶基础上往上爬一阶或两阶。
你可以从第 0 阶或者 第 1 阶开始,请找到到达顶层的最小的代价是多少。
N和cost[i]皆为整数,且N∈[2,1000],cost[i]∈ [0, 999]。
输入描述:
输入为一串半角逗号分割的整数,对应cost数组,例如
10,15,20
输出描述:
输出一个整数,表示花费的最小代价
示例1
输入
复制
1,100,1,1,1,100,1,1,100,1
输出
复制
6

我们来看这题,我不管别人是怎么做的,在我这里,这种题目我不会费脑筋去考虑数学方法,我只会暴力递归然后去优化。也能ac.
这种题目,第一眼应该想到递归的。

因为有一个最小,和让你选择。

那么直接看我的代码。
如果你看了我之前的博客,那么是可以理解我的思路的。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        String[] t = str.split(",");
        int[] cost = new int[t.length];
        visited = new int[cost.length];
        Arrays.fill(visited, -1);
        for(int i = 0; i < t.length; i ++) {
            cost[i] = Integer.valueOf(t[i]);
        }
        System.out.println(Math.min(dfs(cost, 0), dfs(cost, 1)));

    }
    public static int[] visited;
    public static int dfs(int[] cost, int index) {
        if(index >= cost.length)
            return 0;
        if(visited[index] != -1)
            return visited[index];
        int ans = Math.min(dfs(cost, index + 1) + cost[index], dfs(cost, index + 2) + cost[index]);
        visited[index] = ans;
        return ans;
    }
}

题目描述
给定一个正整数数组,它的第 i 个元素是比特币第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一次),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入比特币前卖出。
输入描述:
正整数数组,为以空格分隔的n个正整数
输出描述:
最大利润
示例1
输入
复制
7 1 5 3 6 4
输出
复制
5

这题用峰谷法,去找最小的谷值,然后更新就好了,更新最大值,和谷值。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        String[] t = str.split(" ");
        int[] arr = new int[t.length];
        for(int i = 0; i < t.length; i ++)
            arr[i] = Integer.valueOf(t[i]);
        int lowpoint = Integer.MAX_VALUE;
        int maxProfit = -1;
        for(int i = 0; i < t.length; i ++) {
            lowpoint = Math.min(lowpoint, arr[i]);
            maxProfit = Math.max(maxProfit, arr[i] - lowpoint);
        }
        System.out.println(maxProfit);
    }

}

题目描述
假设你是一位很有爱的幼儿园老师,想要给幼儿园的小朋友们一些小糖果。但是,每个孩子最多只能给一块糖果。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的糖果的最小尺寸;并且每块糖果 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个糖果 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
注意:
你可以假设胃口值为正。
一个小朋友最多只能拥有一块糖果。
输入描述:
第一行输入每个孩子的胃口值
第二行输入每个糖果的尺寸
孩子数和糖果数不超过1000
输出描述:
能满足孩子数量的最大值
示例1
输入
复制
1 2 3
1 1
输出
复制
1

招商银行。简单题,两个sort

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        String str1 = in.nextLine();
        String[] t = str.split(" ");
        String[] a = str1.split(" ");
        int[] child = new int[t.length];
        int[] candy = new int[a.length];
        for(int i = 0; i < t.length; i ++) {
            child[i] = Integer.valueOf(t[i]);
        }
        for(int i = 0; i < a.length; i ++) {
            candy[i] = Integer.valueOf(a[i]);
        }
        
        Arrays.sort(child);
        Arrays.sort(candy);
        int ans = 0;
        int index = 0;
        int p = 0;
        while(index < candy.length && p < child.length) {
            if(candy[index] >= child[p]) {
                index += 1;
                p += 1;
                ans += 1;
            }
            else {
                index += 1;
            }
        }
        System.out.println(ans);
    }
}

题目描述
一条包含字母 A-Z 的消息通过以下方式进行了编码:
‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
输入描述:
12可以解码成“AB”,“L”这两种
输出描述:
解码方法的总数
示例1
输入
复制
12
输出
复制
2
说明
12可以解码成“AB”,“A,B"这两种

这题,有难度,有意思,dfs, dp都可解。
注意的是一般 12 这样的数它有两种可能!但是前提是要<=26, > 0
那么递推关系不就出来了,我们从后面往前推。
leetcode原题,有兴趣的可以去看看,我就不过多解释了。

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        //int[] dp = new int[str.lenngth() + 1];
        visited = new int[str.length() + 1];
        Arrays.fill(visited, -1);
        System.out.println(dfs(str, 0);
    }
    public static int[] visited;
    public static int dfs(String str, int index) {
        if(index == str.length()) return 1;
        if(str.charAt(index) == '0') return 0;
        if(visited[index] != -1) return visited[index]; 
        if((index <= str.length() - 2) && sol(str.charAt(index), str.charAt(index + 1))) {
            visited[index] = dfs(str, index + 2) + dfs(str, index + 1);
            return dfs(str, index + 2) + dfs(str, index + 1);
        }
        visited[index] = dfs(str, index + 1);
        return dfs(str, index + 1);
    }
    
    public static boolean sol(char a, char b) {
        int num = 10 * (a - '0') + (b - '0');
        return num >= 1 && num <= 26;
    }
}

题目描述
解析加减法运算
如:
输入字符串:“1+2+3” 输出:“6”
输入字符串:“1+2-3” 输出:“0”
输入字符串:"-1+2+3" 输出:“4”
输入字符串:“1” 输出:“1”
输入字符串:"-1" 输出:"-1"
已知条件:输入的运算都是整数运算,且只有加减运算
要求:输出为String类型,不能使用内建的eval()函数
输入描述:
输入字符串:“1+2+3”
输出描述:
输出:“6”
示例1
输入
复制
1+2+3
输出
复制
6

这题,是有些麻烦的,我们用两个list分别存储数字和符号,然后准备一个栈。
这题简化了,因为不存在乘除法,我做过一个小红书的题目,那是带乘法的,要更难,所以我这里多写了乘除法的可能。

那么要注意的是,第一个数可能是负数,那么要特殊处理。
先在数字list里面add一个0.
讲一下乘除法。要考虑优先级。
例子 1 + 2 * 3 + 4;
那么就本来是计算1 + 2, 碰到了乘号,那么从numlist中取出一个数字,去入栈,然后取栈顶两个相乘,再压入栈。
注意边界情况的考虑,这题坑有些多的。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        solution(str);
    }
    
    public static void solution(String str) {
        LinkedList<Integer> numlist = new LinkedList<>();
        LinkedList<Character> opsList = new LinkedList<>();
        
        Stack<Integer> stack = new Stack<>();
        int index = 0;
        if(str.charAt(0) == '-') numlist.add(0);
        while(index < str.length()) {
            if(str.charAt(index) >= '0' && str.charAt(index) <= '9') {
                int start = index;
                while(index < str.length() && str.charAt(index) >= '0' && str.charAt(index) <= '9') {
                    index += 1;
                }
                String t = index == str.length() - 1 ? str.substring(index) : str.substring(start, index);
                numlist.add(Integer.valueOf(t));
            } else {
                opsList.add(str.charAt(index));
                index += 1;
            }
        }
        if(numlist.size() < 2) {
            if(opsList.size() == 0) {
                 System.out.println(numlist.poll());
            return ;
            } 
           System.out.println(opsList.poll() + "" + numlist.poll());
           return ;
        }
        
        stack.push(numlist.poll());
        stack.push(numlist.poll());
        
        while(!opsList.isEmpty()) {
            char ch = opsList.poll();
            if((ch == '+' || ch == '-') && (!opsList.isEmpty() && opsList.getFirst() == '*')) {
                if(!numlist.isEmpty()) {
                    stack.push(numlist.poll());
                    int x = stack.pop();
                    int y = stack.pop();
                    stack.push(x * y);
                    opsList.poll();
                    opsList.addFirst(ch);
                } else return ;
            } else {
                if(ch == '+') {
                    int x = stack.pop();
                    int y = stack.pop();
                    stack.push(x + y);
                } 
                else if(ch == '-') {
                    int x = stack.pop();
                    int y = stack.pop();
                    stack.push(y - x);
                }
                if(!numlist.isEmpty())
                    stack.push(numlist.poll());
            }
        }
        System.out.println(String.valueOf(stack.pop()));
    }
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页