奇妙的算法【10】TX--有效号码、最,小耗时、最小差值、差值输出、异或结果
昨晚刚刚写的几道算法题,难度也还行,就是全部AC有些困难,当时第一题AC、第二题AC 60%,第四题AC 40%,第五题没有时间写完了,这个应该全部AC了;其中第三题没有写出来
1,是否存在符合规范的有效号码
某个国家的电话号码规范为:①以8开头;②长度为11位
现在给出任意长度的一串数字,判断是否可以通过从头部或者尾部连续删除获得一串符合规范的电话号码?
下面的代码是我第一次就写好的、后期没有优化的,感觉也没什么可以优化的空间了【使用subString还可以在缩小搜索范围】,这个题目一次通过
package com.cnblogs.mufasa.Main1; import java.util.Scanner; public class Main { public static void main(String[] args) { //0,测试 //1,输入 Scanner sc=new Scanner(System.in); int t=sc.nextInt(); for(int i=0;i<t;i++){ sc.next(); String str=sc.next(); int loc=str.indexOf("8"); if(loc!=-1&&str.length()-loc>=11){ System.out.println("YES"); }else{ System.out.println("NO"); } } //2,处理 //3,输出 } } /* 4 8 8888888888888 8 18111111 13 18111111111111 10 11118111111 */
2,完成任务的最小耗时是多少
有M个程序员【M为偶数】,每个程序员的拖延症拖延时间为Ti,同时有M/2个编程任务,每个编程任务需要两个程序一起解决,先求解全部任务的最小拖延耽误时间是多少?【两个程序员拖延时间相加为每个任务的拖延时间】
我的第一次解答编程为:【在原有基础上,自己思考了一些测试用例检查出来没有全部AC的部分原因】
package com.cnblogs.mufasa.Main2_1; import java.util.Arrays; import java.util.Scanner; class Node implements Comparable<Node>{ int num; int time; public Node(int num,int time){ this.num=num; this.time=time; } @Override public int compareTo(Node o) { return time-o.time; } } public class Main { public static void main(String[] args) { //0,测试 //1,输入 Scanner sc=new Scanner(System.in); int n=sc.nextInt(); Node[] arr=new Node[n]; for(int i=0;i<n;i++){ int num=sc.nextInt(); int time=sc.nextInt(); arr[i]=new Node(num,time); } //2.1,处理 Arrays.sort(arr); //2.2,处理 int x=0,y=n-1,maxTime=0; while (x!=y&&x+1!=y){ if(arr[x].time+arr[y].time>maxTime){ maxTime=arr[x].time+arr[y].time; } if(arr[x].num>arr[y].num){ y--; arr[x].num-=arr[y].num; }else if(arr[x].num<arr[y].num){ x++; arr[y].num-=arr[x].num; }else { x++; y--; } } if(arr[x].time+arr[y].time>maxTime){ maxTime=arr[x].time+arr[y].time; } //3,输出 System.out.println(maxTime); } } /* M名员工,第i名员工有拖延时间ti 有M/2分工作需要完成,每份工作需要安排2名员工 测试用例1:AC 30% 3 1 8 2 6 1 2 测试用例2:这个第一次没有通过,光标判断不完善导致 4 1 8 1 5 1 2 1 6 测试用例3:测试通过 4 3 8 1 5 1 2 1 6 */
3,两组人员最小差值
题目: 将一个数组分成两部分,不要求两部分所包含的元素个数相等,要求使得这两个部分的和的差值最小。比如对于数组{1,0,1,7,2,4},可以分成{1,0,1,2,4}和{7},使得这两部分的差值最小。
这个我当时没有思路【其实有一个遍历的思路,但是他们题目的输入范围大小一看就知道这种方法是不行的】
思路:差最小就是说两部分的和最接近,而且和所有数的和SUM的一半也是最接近的。假设用sum1表示第一部分的和,sum2表示第二部分的和,SUM表示所有数的和,那么sum1+sum2=SUM。假设sum1<sum2 那么SUM/2-sum1 = sum2-SUM/2;
所以我们就有目标了,使得sum1<=SUM/2的条件下尽可能的大。也就是说从n个数中选出某些数,使得这些数的和尽可能的接近或者等于所有数的和的一般。这其实就是简单的背包问题了:
背包容量是SUM/2. 每个物体的体积是数的大小,然后尽可能的装满背包。
dp方程:f[i][V] = max(f[i-1][V-v[i]]+v[i], f[i-1][V] )
f[i][V]表示用前i个物体装容量为V的背包能够装下的最大值,f[i-1][V-v[i]]+v[i]表示第i个物体装进背包的情况,f[i-1][V]表示第i件物品不装进背包的情况。
dp动态规划求解,空间复杂度较高,变成了一个背包问题
package com.cnblogs.mufasa.Main3.Demo; import java.util.Arrays; public class Dp_backpack { public static void match(int[] arr){ int sum = Arrays.stream(arr).sum(); int len = arr.length; int halfOfSum = sum/2; int matrix_firstDimensionLen = len+1; int matrix_secondDimensionLen = halfOfSum+1; int[][] matrix = new int[matrix_firstDimensionLen][matrix_secondDimensionLen]; for (int i = 1; i < matrix_firstDimensionLen; i++) { for (int j = 1; j < matrix_secondDimensionLen; j++) { //如果第i件物体不装进背包 matrix[i][j] = matrix[i-1][j]; //如果第i件物体装进背包 //备注:j - arr[i-1] >= 0防止下标为负 if(j - arr[i-1] >= 0 && matrix[i - 1][j - arr[i-1]] + arr[i-1] > matrix[i][j]){ matrix[i][j] = matrix[i - 1][j - arr[i-1]] + arr[i-1]; } } } System.out.print(matrix[len][halfOfSum]+"\t"); System.out.println(sum-matrix[len][halfOfSum]); } public static void main(String[] args){ int[] arr = {1,2,3,4,5}; match(arr); } }
参考链接:
https://blog.csdn.net/baidu_37107022/article/details/73123817
https://www.cnblogs.com/ranjiewen/p/9085049.html
4,相差输出
有一组无序的正整数数组,每次输出其最小的正整数,其他所有数字减去这个数,如果所有的数据都为0或者负数,那么直接输出0,这个过程进行k轮
我的思路是先进行由小到大的排序,之后从头到尾进行逐项判断输出,并且更新当前需要减去的数值大小!,时间复杂度为O(logn+k)
package com.cnblogs.mufasa.Main4; import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(String[] args) { //0,测试 //1,输入 Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int k=sc.nextInt(); int[] arr=new int[n]; for(int i=0;i<n;i++){ arr[i]=sc.nextInt(); } //2,处理 Arrays.sort(arr); int preNum=0; boolean flag=false; int loc=0; for(int i=0;i<k;i++){ if(loc>=n){ System.out.println(0); }else { int temp=arr[loc]-preNum; if(temp<=0){//需要跳到下一个位置 loc=SinNext(arr,preNum,loc+1); }else {//不小于零 System.out.println(temp); preNum+=temp; loc++; } } } //3,输出 } private static int SinNext(int[] arr,int preNum,int loc){//递归调用这里 if(loc>arr.length-1){//直接输出0 System.out.println(0); return arr.length; }else { int temp=arr[loc]-preNum; if(temp<=0){//需要跳到下一个位置 loc=SinNext(arr,preNum,loc+1); }else {//不小于零 System.out.println(temp); preNum+=temp; loc++; } } return loc; } } /* 7 5 5 8 10 3 6 10 8 5 5 1 1 1 1 1 4 5 3 1 3 5 */
5,异或输出
有两组正整数数组,他们对方都在各个任取一个相加组成新的数组的内容,例如:
1 2 1 0 0
1 2 3 0 0
你那么新数组就有5*5=25个元素
将这25个元素全部互相取异或将最后结果输出。这里需要用到数学相关的知识:①异或;②异或;③异或;
两个相同的数值异或为0;0与任何数值异或为这个数值本身;
例如:
①5^5=0;123^123=0;
②0^1=1;0^15632=15632;
所以我们只要判断出结果中奇数个的数值,将他们异或一次即可得出正确结果;
并且原始两个数组中偶数倍出现的数值可以直接忽略掉,因为偶数倍出现的数值和另外一组数据的任何数值相加也都是相同数值偶数倍出现,那么异或之后必定为0;
关于算法复杂度的问题:其实还好,首先使用的不是穷举法;其次将冗余的一些计算直接掐掉了;算法复杂度大致为O((logn)^2)
package com.cnblogs.mufasa.Main5; import java.util.*; public class Main { public static void main(String[] args) { //0,测试 //1,输入 Scanner sc=new Scanner(System.in); int n=sc.nextInt(); TreeMap<Integer,Integer> tm1=new TreeMap<>(); TreeMap<Integer,Integer> tm2=new TreeMap<>(); //2,处理 for(int i=0;i<n;i++){ int temp=sc.nextInt(); Object num=tm1.get(temp); if(num!=null){ tm1.put(temp,((int) num)+1); }else { tm1.put(temp,1); } } for(int i=0;i<n;i++){ int temp=sc.nextInt(); Object num=tm2.get(temp); if(num!=null){ tm2.put(temp,((int) num)+1); }else { tm2.put(temp,1); } } ArrayList<Integer> arrayList1=new ArrayList<>(); ArrayList<Integer> arrayList2=new ArrayList<>(); for(Map.Entry<Integer,Integer> kv:tm1.entrySet()){ if((kv.getValue()^1)==0){ arrayList1.add(kv.getKey()); } } for(Map.Entry<Integer,Integer> kv:tm2.entrySet()){ if((kv.getValue()^1)==0){ arrayList2.add(kv.getKey()); } } int temp=0; for(int i=0;i<arrayList1.size();i++){ for(int j=0;j<arrayList2.size();j++){ temp^=(arrayList1.get(i)+arrayList2.get(j)); } } System.out.print(temp); //3,输出 } } /* 5 1 2 1 0 0 1 2 3 0 0 2//样例1输出结果 6 4 6 0 0 3 3 0 5 6 5 0 3 8//样例2输出结果 */