java知识和练习

更多java基础知识点击这里:https://zhuanlan.zhihu.com/p/64147696

有 n 个字符串,每个字符串都是由 A-J 的大写字符构成。现在你将每个字符映射为一个 0-9 的数字,不同字符映射为不同的数字。这样每个字符串就可以看做一个整数,唯一的要求是这些整数必须是正整数且它们的字符串不能有前导零。现在问你怎样映射字符才能使得这些字符串表示的整数之和最大?

import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
 
/**
 * ABC=100×A+10×B+C
 * BCA=100×B+10×C+A
 * ABC+BCA=110×B+101×A+11×C
 * 要使和最大,则权值越大的映射的数字应越大
 */
public class Main {
 
    static class Element {
        long w;//权值
        boolean flag;//不能为0
    }
 
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNext()) {
            int n;
            Element[] es = new Element[10];
            for (int i = 0; i < 10; i++) {
                es[i] = new Element();
            }
            n = scan.nextInt();
            for (int i = 0; i < n; i++) {
                String str = scan.next();
                calWeight(es, str);
            }
            System.out.println(sovle(es));
        }
        scan.close();
    }
 
    private static long sovle(Element[] es) {
        long res = 0;
        Arrays.sort(es, new Comparator<Element>() {
            @Override
            public int compare(Element e1, Element e2) {
                return e1.w > e2.w ? 1 : (e1.w == e2.w ? 0 : -1);
            }
        });
        //权值最低且不能为0
        if (es[0].flag) {
            int i;
            //权值最小可以为0字母
            for (i = 1; i < 10; i++) {
                if (!es[i].flag) {
                    break;
                }
            }
            Element temp = es[i];
            for (; i > 0; i--) {
                es[i] = es[i - 1];
            }
            es[0] = temp;
        }
        for (int i = 9; i >= 0; i--) {
            res += es[i].w * i;
        }
        return res;
    }
 
    private static void calWeight(Element[] es, String str) {
        int len = str.length();
        long base = 1;
        for (int i = len - 1; i >= 0; i--, base *= 10) {
            int index = str.charAt(i) - 'A';
            es[index].w += base;
            if (i == 0) {//首字母不能为0
                es[index].flag = true;
            }
        }
    }
}

有一个由很多木棒构成的集合,每个木棒有对应的长度,请问能否用集合中的这些木棒以某个顺序首尾相连构成一个面积大于 0 的简单多边形且所有木棒都要用上,简单多边形即不会自交的多边形。

初始集合是空的,有两种操作,要么给集合添加一个长度为 L 的木棒,要么删去集合中已经有的某个木棒。每次操作结束后你都需要告知是否能用集合中的这些木棒构成一个简单多边形。

输入描述:

每组测试用例仅包含一组数据,每组数据第一行为一个正整数 n 表示操作的数量(1 ≤ n ≤ 50000) , 接下来有n行,每行第一个整数为操作类型 i (i ∈ {1,2}),第二个整数为一个长度 L(1 ≤ L ≤ 1,000,000,000)。如果 i=1 代表在集合内插入一个长度为 L 的木棒,如果 i=2 代表删去在集合内的一根长度为 L 的木棒。输入数据保证删除时集合中必定存在长度为 L 的木棒,且任意操作后集合都是非空的。


输出描述:

对于每一次操作结束有一次输出,如果集合内的木棒可以构成简单多边形,输出 "Yes" ,否则输出 "No"。

示例1

输入

5
1 1
1 1
1 1
2 1
1 2

输出

No
No
Yes
No
No
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();
        int num = 0;
        int j = 0;
        int max = 0;
 
        List<Integer> list = new ArrayList<>();
        while (j++ < n) {
            int i = sc.nextInt();
            int l = sc.nextInt();
            sc.nextLine();
            if (i == 1) {
                list.add(l);
                num += l;
            } else {
                list.remove(list.indexOf(l));
                num -= l;
            }
            Collections.sort(list);
             
            if(list.size() > 0){
                max = list.get(list.size()-1);
            }
            if (num - max <= max) {
                System.out.println("No");
            } else {
                System.out.println("Yes");
            }
        }
    }
}

 

给出 n 个字符串,对于每个 n 个排列 p,按排列给出的顺序(p[0] , p[1] … p[n-1])依次连接这 n 个字符串都能得到一个长度为这些字符串长度之和的字符串。所以按照这个方法一共可以生成 n! 个字符串。

一个字符串的权值等于把这个字符串循环左移 i 次后得到的字符串仍和原字符串全等的数量,i 的取值为 [1 , 字符串长度]。求这些字符串最后生成的 n! 个字符串中权值为 K 的有多少个。

注:定义把一个串循环左移 1 次等价于把这个串的第一个字符移动到最后一个字符的后面。

 递归生成全排列,判断权值,也就是串能分出多少个相同的子串,用KMP可解,
 
    判断n-next[n]能否整除n,可以知道串是否由多个相同字串组成,
 
    除完的商就是权值,不能整除的串权值为1.
 
     
     
        import java.util.*;
public class Main{
    static ArrayList<String> res;
    public static int next(String arr){
        int[] next=new int[arr.length()+1];
        int res=1;
        next[0]=next[1]=0;
        int j=0;
        for(int i=1;i<arr.length();i++){
            while(j>0&&arr.charAt(i)!=arr.charAt(j)) j=next[j];
            if(arr.charAt(i)==arr.charAt(j)) {
                j++;
            }
            next[i+1]=j;
        }
        if(arr.length()%(arr.length()-next[arr.length()])==0)
            res=arr.length()/(arr.length()-next[arr.length()]);
        return res;
    }
    public static void allString(String[] strr,int s,int n){
        String tmp;
        if(s==(n-1)){
            tmp="";
            for(int i=0;i<n;i++){
                tmp+=strr[i];
            }
            res.add(tmp);
        } 
        for(int i=s;i<n;i++){
            tmp=strr[s];
            strr[s]=strr[i];
            strr[i]=tmp;
            allString(strr,s+1,n);
            tmp=strr[s];
            strr[s]=strr[i];
            strr[i]=tmp;
        }
    }
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n,k,count;
        String[] strr;
        while(sc.hasNext()){
            res=new ArrayList<String>();
            count=0;
            n=sc.nextInt();
            k=sc.nextInt();
            strr=new String[n];
            for(int i=0;i<n;i++){
                strr[i]=sc.next();
            }
            allString(strr,0,n);
            for(int i=0;i<res.size();i++){
                if(next(res.get(i))==k)
                    count++;
            }
            System.out.println(count);
        }
        sc.close();
    }
}
    

为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。

 

输入描述:
输入: 第1行为n代表用户的个数 第2行为n个整数,第i个代表用户标号为i的用户对某类文章的喜好度 第3行为一个正整数q代表查询的组数  第4行到第(3+q)行,每行包含3个整数l,r,k代表一组查询,
即标号为l<=i<=r的用户中对这类文章喜好值为k的用户的个数。 数据范围n <= 300000,q<=300000 k是整型

输出描述:
输出:一共q行,每行一个整数代表喜好值为k的用户的个数

输入例子1:
5
1 2 3 3 5
3
1 2 1
2 4 5
3 5 3

输出例子1:
1
0
2

例子说明1:
样例解释:
有5个用户,喜好值为分别为1、2、3、3、5,
第一组询问对于标号[1,2]的用户喜好值为1的用户的个数是1
第二组询问对于标号[2,4]的用户喜好值为5的用户的个数是0
第三组询问对于标号[3,5]的用户喜好值为3的用户的个数是2
import java.util.*;

public class UsrFav {

    public static void main (String[] args) {

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        HashMap<Integer, List<Integer>> hs = new HashMap<>();

        for (int i=0; i < n; i++) {
            List<Integer> list = new ArrayList<>();
            int tmp = sc.nextInt();
            if (hs.get(tmp)!= null){
               list = hs.get(tmp);
            }
            list.add(i+1);
            hs.put(tmp, list);
        }

        int gs = sc.nextInt();
        for (int i=0; i < gs; i++){
            int lf = sc.nextInt();
            int rt = sc.nextInt();
            int fav = sc.nextInt();

            if (hs.get(fav) == null) {
                System.out.println(0);
                continue;
            }

            List<Integer> ls = hs.get(fav);
            int count = 0;

            //有序链表,此处可以先使用折半查找找到起始位置优化
            for (int j=0; j < ls.size(); j++) {
                if (ls.get(j) > rt)
                    break;
                if (ls.get(j) < lf)
                    continue;
                count++;
            }
            System.out.println(count);

        }


    }


}

作为一个手串艺人,有金主向你订购了一条包含n个杂色串珠的手串——每个串珠要么无色,要么涂了若干种颜色。为了使手串的色彩看起来不那么单调,金主要求,手串上的任意一种颜色(不包含无色),在任意连续的m个串珠里至多出现一次(注意这里手串是一个环形)。手串上的颜色一共有c种。现在按顺时针序告诉你n个串珠的手串上,每个串珠用所包含的颜色分别有哪些。请你判断该手串上有多少种颜色不符合要求。即询问有多少种颜色在任意连续m个串珠中出现了至少两次。

 

输入描述:
第一行输入n,m,c三个数,用空格隔开。(1 <= n <= 10000, 1 <= m <= 1000, 1 <= c <= 50) 接下来n行每行的第一个数num_i(0 <= num_i <= c)表示第i颗珠子有多少种颜色。
接下来依次读入num_i个数字,每个数字x表示第i颗柱子上包含第x种颜色(1 <= x <= c)

输出描述:
一个非负整数,表示该手链上有多少种颜色不符需求。

输入例子1:
5 2 3
3 1 2 3
0
2 2 3
1 2
1 3

输出例子1:
2
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int c = sc.nextInt();
        byte[][] matrix = new byte[n][c];
        for (int i=0; i<n; i++) {
            int total = sc.nextInt();
            for (int j=0; j<total; j++) {
                int k = sc.nextInt();
                matrix[i][k-1] = 1;
            }
        }
        byte[] result = new byte[c];
        for (int i=0; i<c; i++) {
            int lastIndex = -1;
            int end = n+m-1;
            //System.out.println("end is:" + end);
            for (int j=0; j<end; j++) {
                int row = j%n;
                if(matrix[row][i]==1) {
                    if (lastIndex==-1) lastIndex = j;
                    else {
                        if (j-lastIndex < m) result[i] = 1;
                        else {
                            lastIndex = j;
                        }
                    }
                }
            }
        }
        int sum = 0;
        for (int i=0; i<c; i++) {
            if (result[i] ==1) sum++;
        }
        System.out.println(sum);
    }
}

 

方式二

思想:比较通俗易懂,统计每一个颜色出现的位置,使用数据结构Map<颜色,LinkedList颜色的位置>
然后统计每一种颜色是否出错,如果出错,就break,error+1

importjava.util.HashMap;
 
importjava.util.LinkedList;
 
importjava.util.Map;
 
importjava.util.Scanner;
 
  
 
publicclassMain {
 
  
 
    publicstaticvoidmain(String[] args) {
 
        Scanner scanner = newScanner(System.in);
 
        intn = scanner.nextInt();// n个手串
 
        intm = scanner.nextInt();// 间隔为m
 
        intc = scanner.nextInt();// 有c种颜色
 
        Map<Integer, LinkedList<Integer>> map = newHashMap<Integer, LinkedList<Integer>>();
 
        for(inti = 1; i <= c; i++) {
 
            map.put(i, newLinkedList<Integer>());
 
        }
 
        inttotal = 1;
 
        while(total <= n) {
 
            intnum = scanner.nextInt();// 表示有多少顔色
 
            for(inti = 0; i < num; i++) {
 
                intcolor = scanner.nextInt();
 
                LinkedList<Integer> linkedList = map.get(color);// 得到某種顔色的位置
 
                linkedList.add(total);// 再加上此位置
 
                map.put(color, linkedList);
 
            }
 
            total++;
 
        }
 
        interror = 0;
 
        for(inti = 1; i <= c; i++) {
 
            LinkedList<Integer> linkedList = map.get(i);// 得到某種顔色的位置
 
            int[] array = newint[linkedList.size()];
 
            intk = 0;
 
            for(intj : linkedList) {
 
                array[k++] = j;
 
            }
 
            for(intj = 0; j < array.length; j++) {
 
                if(j + 1< array.length && array[j + 1] - array[j] < m) {
 
                    error++;
 
                    break;
 
                } elseif(j + 1== array.length && array[0] + n - array[j] < m) {
 
                    error++;
 
                    break;
 
                }
 
            }
 
        }
 
        System.out.println(error);
 
    }
 
}

 

【编码题】字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?

 

输入描述:
第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)

输出描述:
一个非负整数,表示操作之后,连续最长的相同字母数量。

输入例子1:
abcbaa 2

输出例子1:
2
import java.util.*;
    
    public class CharMax {
    
        public static void main (String[] args) {
            HashMap<Character, ArrayList<Integer>> hs = new HashMap<>();
            int max = 0;//最大连续数
    
            Scanner sc = new Scanner(System.in);
            String[] arr = sc.nextLine().split("\\s+");
            String str = arr[0];
            int steps = Integer.parseInt(arr[1]);//总步长
    
            //准备工作
            for(int i=0; i < str.length(); i++){
                char c = str.charAt(i);
    
                ArrayList<Integer> ls = new ArrayList<>();
                if (hs.get(c) != null){
                    ls = hs.get(c);
                }
                ls.add(i);
                hs.put(c, ls);
            }
    
            //开始计算
            for (char key : hs.keySet()){
                ArrayList<Integer> ls = hs.get(key);
                int len = ls.size();
                if (len <= max)
                    continue;
                if (len == 1){
                    max = 1;
                    continue;
                }
    
    
                for (int i=0; i < ls.size()-1; i++){
                    int total = 1;//统计连续数
                    int rest = steps;//可走步长数
    
                    int l = i;//左边界
                    int r = i;//右边界
    
                    while( l > 0 || r < ls.size()-1){
                        //左右边界距离下一个有效值计算
                        int l_len = Integer.MAX_VALUE;//左边距
                        int r_len = Integer.MAX_VALUE;//右边距
                        if (l > 0){
                            l_len = (ls.get(i) - (i-l)) - ls.get(l-1) - 1;
                        }
                        if (r < ls.size()-1){
                            r_len = ls.get(r+1) - (ls.get(i) + (r-i)) - 1;
                        }
    
                        if (l_len < r_len){//左边距 < 右边距
                            rest -= l_len;
                            if (rest < 0)
                                break;
    
                            l--;//边界变更
                            total++;
                        }else{
                            rest -= r_len;
                            if (rest < 0)
                                break;
    
                            r++;
                            total++;
                        }
    
                    }
    
                    if (total > max)
                        max = total;
                }
    
            }
    
    
            System.out.println(max);
    
        }
    
    
    
    }
    

方式二

import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int m = sc.nextInt();
        Map<Character, List> map = new HashMap<>(26); // key为字符串中的每个字母,value记录该字母在字符串中出现的位置
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            List list = map.get(c);
            if (list == null)
                map.put(c, list = new ArrayList<Integer>(100));
            list.add(i);
        }
        int maxLen = 1; // 记录连续最长的相同字母数量
        // 遍历map
        for (Map.Entry<Character, List> entry : map.entrySet()) {
            List<Integer> arrayList = entry.getValue();
            // 遍历字母在字符串中出现的位置
            for (int i = 0; i < arrayList.size(); i++) {
                int ctr = arrayList.get(i); // 以当前遍历的元素位置为中心,计算其他相同元素到到该中心需移动的步数
                int[] move = new int[arrayList.size()];
                // 获取 move[],表示每个相同字母到中心点 ctr 需要移动的最少步数
                for (int j = 0; j < arrayList.size(); j++)
                    move[j] = (Math.abs(arrayList.get(j) - ctr) -
                            Math.abs(i - j));
                // 排序后,选择移动代价最少的前 k + 1 个
                Arrays.sort(move);
                int sum = 0; // 记录移动步数之和
                for (int k = 0; k < move.length; k++) {
                    sum += move[k];
                    if (sum > m)
                        break;
                    // 每有一个字母移动到中心点,该字母的连续相同数量就增加1
                    if (k + 1 > maxLen)
                        maxLen = k + 1;
                }
            }
        }
        System.out.println(maxLen);
    }
}
我叫王大锤,是一家出版社的编辑。我负责校对投稿来的英文稿件,这份工作非常烦人,因为每天都要去修正无数的拼写错误。但是,优秀的人总能在平凡的工作中发现真理。我发现一个发现拼写错误的捷径:
 
1. 三个同样的字母连在一起,一定是拼写错误,去掉一个的就好啦:比如 helllo -> hello
2. 两对一样的字母(AABB型)连在一起,一定是拼写错误,去掉第二对的一个字母就好啦:比如 helloo -> hello
3. 上面的规则优先“从左到右”匹配,即如果是AABBCC,虽然AABB和BBCC都是错误拼写,应该优先考虑修复AABB,结果为AABCC
 
 
我特喵是个天才!我在蓝翔学过挖掘机和程序设计,按照这个原理写了一个自动校对器,工作效率从此起飞。用不了多久,我就会出任CEO,当上董事长,迎娶白富美,走上人生巅峰,想想都有点小激动呢!
……
万万没想到,我被开除了,临走时老板对我说: “做人做事要兢兢业业、勤勤恳恳、本本分分,人要是行,干一行行一行。一行行行行行;要是不行,干一行不行一行,一行不行行行不行。” 我现在整个人红红火火恍恍惚惚的……
 
请听题:请实现大锤的自动校对程序

输入描述:
第一行包括一个数字N,表示本次用例包括多少个待校验的字符串。

后面跟随N行,每行为一个待校验的字符串。

输出描述:
N行,每行包括一个被修复后的字符串。

输入例子1:
2
helloo
wooooooow

输出例子1:
hello
woow
import java.util.*;
public class Main{
    public static void main(String []args)
    {
        Scanner scanner = new Scanner(System.in);
        int line = scanner.nextInt();
        scanner.nextLine();
        for (int i = 0; i < line; i++) {
            System.out.println(scanner.nextLine().replaceAll("(.)\\1+","$1$1").replaceAll("(.)\\1(.)\\2","$1$1$2"));
        }
    }
    }

 

我叫王大锤,是一名特工。我刚刚接到任务:在字节跳动大街进行埋伏,抓捕恐怖分子孔连顺。和我一起行动的还有另外两名特工,我提议

1. 我们在字节跳动大街的N个建筑中选定3个埋伏地点。
2. 为了相互照应,我们决定相距最远的两名特工间的距离不超过D。

我特喵是个天才! 经过精密的计算,我们从X种可行的埋伏方案中选择了一种。这个方案万无一失,颤抖吧,孔连顺!
……
万万没想到,计划还是失败了,孔连顺化妆成小龙女,混在cosplay的队伍中逃出了字节跳动大街。只怪他的伪装太成功了,就是杨过本人来了也发现不了的!

请听题:给定N(可选作为埋伏点的建筑物数)、D(相距最远的两名特工间的距离的最大值)以及可选建筑的坐标,计算在这次行动中,大锤的小队有多少种埋伏选择。
注意:
1. 两个特工不能埋伏在同一地点
2. 三个特工是等价的:即同样的位置组合(A, B, C) 只算一种埋伏方法,不能因“特工之间互换位置”而重复使用

 

输入描述:
第一行包含空格分隔的两个数字 N和D(1 ≤ N ≤ 1000000; 1 ≤ D ≤ 1000000)

第二行包含N个建筑物的的位置,每个位置用一个整数(取值区间为[0, 1000000])表示,从小到大排列(将字节跳动大街看做一条数轴)


输出描述:
一个数字,表示不同埋伏方案的数量。结果可能溢出,请对 99997867 取模
示例1

输入

4 3
1 2 3 4

输出

4

说明

可选方案 (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)
示例2

输入

5 19
1 10 20 30 50

输出

1

说明

可选方案 (1, 10, 20)
//很多人说复杂度会比较高,认为内层循环需要要二叉查找降低复杂度,这个思路确实可行。
但是实际上,对于第二层以j为下标的循环,我们完全不需要每次都从j=i+2进行循环,可以单独用变量right存放上次循环的结果,下一次循环直接从j=right开始就可以了。
import java.util.Scanner;
 
public class Main
{
 
    public static void main(String[] args)
    {
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            int N=in.nextInt();
            int D=in.nextInt();
            int [] location =new int [N];
            for(int i=0 ;i<N;i++){
                location[i]=in.nextInt();  
            }
            long count =0L;
             
            int right=2;
            for(int i=0;i<N-2;i++){
                long temp=0L;
                for(int j=right;j<N;j++) {
                     
                    if(location[j]-location[i]>D) {
                        break;
                    }else {
                        temp=(long)(j-i);
                        right=j;
                    }
                     
                }
                if(temp>=2)
                    count+=temp*(temp-1)/2%99997867;
                 
                 
                 
            }
            System.out.println(count%99997867);
             
             
        }
         
 
    }
 
}
  小明是一名算法工程师,同时也是一名铲屎官。某天,他突发奇想,想从猫咪的视频里挖掘一些猫咪的运动信息。为了提取运动信息,他需要从视频的每一帧提取“猫咪特征”。一个猫咪特征是一个两维的vector<x, y>。如果x_1=x_2 and y_1=y_2,那么这俩是同一个特征。
       因此,如果喵咪特征连续一致,可以认为喵咪在运动。也就是说,如果特征<a, b>在持续帧里出现,那么它将构成特征运动。比如,特征<a, b>在第2/3/4/7/8帧出现,那么该特征将形成两个特征运动2-3-4 和7-8。
现在,给定每一帧的特征,特征的数量可能不一样。小明期望能找到最长的特征运动。
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        for(int i = 0; i < N; ++i){
            HashMap<String, Integer> mem = new HashMap<>();
            HashMap<String, Integer> temp_mem = new HashMap<>();
            int M = sc.nextInt();
            int max = 1;
            for(int j = 0; j < M; ++j){
                temp_mem.clear();
                int n = sc.nextInt();
                for(int k = 0; k < n; ++k){
                    int x = sc.nextInt();
                    int y = sc.nextInt();
                    String key = String.valueOf(x) + " " + String.valueOf(y);
                    temp_mem.put(key, mem.getOrDefault(key, 0) + 1);
                    max = Math.max(temp_mem.get(key), max);
                }
                mem.clear();
                mem.putAll(temp_mem);
            }
            if(max <= 1){
                System.out.println(1);
            }else{
                System.out.println(max);
            }
        }
 
    }
}

 

posted @ 2020-06-20 14:44  To_Yang  阅读(273)  评论(0)    收藏  举报