算法总结2

题目1:牛牛有一个鱼缸。鱼缸里面已经有n条鱼,每条鱼的大小为fishSize[i](1<=i<=n,n为正整数),牛牛现在想把新捕捉的鱼放入鱼缸。鱼缸内存在着大鱼吃小鱼的定律。经观察,牛牛发现一条鱼A的大小为另外一条鱼B大小的2倍到10倍(包括2倍大小和10倍大小),鱼A会吃掉鱼B.考虑这个,牛牛要放入的鱼需要保证:1.放进去的鱼是安全的,不会被其他鱼吃掉 2。这条鱼放进去也不能吃掉其他鱼 鱼缸里已经存在的鱼相处了很久,不考虑他们互相捕食,现在知道新放入鱼的大小范围【minSize,maxSize】(考虑鱼的大小都是整数)牛牛想知道多少种大小的鱼可以放入这个鱼缸。

输入数据包括3行.
第一行为新放入鱼的尺寸范围minSize,maxSize(1 ≤ minSize,maxSize ≤ 1000),以空格分隔。

第二行为鱼缸里面已经有鱼的数量n(1 ≤ n ≤ 50)

第三行为已经有的鱼的大小fishSize[i](1 ≤ fishSize[i] ≤ 1000),以空格分隔。
思路:暴力遍历从minSize到maxSize的尺寸,只要满足既不被 鱼缸内鱼吃掉又不会吃掉鱼缸内任意的鱼既符合条件,

code:

public static int getMaxkinds(int minSize,int maxSize,int[] fishes){
    Set<Integer> sizeOfFishes = new HashSet<>();
    int j;
    //找出所有满足不吃池内鱼的尺寸
   for(int i =minSize;i<=maxSize;i++){
       boolean canInput = true;
       for(j =0;j<fishes.length;j++){
          if((i>=fishes[j]*2&&i<=fishes[j]*10)||(fishes[j]<=i*10&&fishes[j]>=i*2)){//如果放进去鱼被会吃或者吃鱼缸里的鱼
              canInput = false;
              break;
          }
       }
        if(canInput){  
           sizeOfFishes.add(i);
        }
   }

    return sizeOfFishes.size();
}
题目2:如果一个单词通过循环右移获得的单词,我们称这些单词都为一种循环单词。 例如:picture 和 turepic 就是属于同一种循环单词。 现在给出n个单词,需要统计这个n个单词中有多少种循环单词。

输入描述:

输入包括n+1行:

第一行为单词个数n(1 ≤ n ≤ 50)

接下来的n行,每行一个单词word[i],长度length(1 ≤ length ≤ 50)。由小写字母构成
输出描述:

输出循环单词的种数

思路:从头到尾遍历,将首次出现的字符串放入list中,然后后面的字符串和list里的字符串比较,如果不存在就放入。

code:

public static int getStringNumbers(String[] lines){
    List<String> list = new ArrayList();
    list.add(lines[0]);
    for(int i=1;i<lines.length;i++){
        int j = 0;
        for(j =0;j<list.size();j++){
            if(isEqual(list.get(j),lines[i]))
                break;
        }
        if(j==list.size()){
            list.add(lines[i]);
        }
    }

    return list.size();
}
//判断desc是否可以通过original移动得到
public static boolean isEqual(String original,String desc){
    if(original.length()!=desc.length())
        return false;
    StringBuilder sb = new StringBuilder(original);
    for(int i = original.length()-1;i>0;i--){
        if((sb.substring(i)+sb.substring(0,i)).equals(desc)){
            return true;
        }
    }
    return false;
}
题目三:DNA分子是以4种脱氧核苷酸为单位连接而成的长链,这4种脱氧核苷酸分别含有A,T,C,G四种碱基。碱基互补配对原则:A和T是配对的,C和G是配对的。如果两条碱基链长度是相同的并且每个位置的碱基是配对的,那么他们就可以配对合成为DNA的双螺旋结构。现在给出两条碱基链,允许在其中一条上做替换操作:把序列上的某个位置的碱基更换为另外一种碱基。问最少需要多少次让两条碱基链配对成功。

输入描述:

输入包括一行:
包括两个字符串,分别表示两条链,两个字符串长度相同且长度均小于等于50。
输出描述:
输出一个整数,即最少需要多少次让两条碱基链配对成功
思路:因为A只有和T才能配对,同样C只能和G配对,那么可以这样分析,只要两条字符串对应的每个字符的差值的绝对值恰好是19('T'-'A=19)'或者4('G'-'C'=4)就好, 如果都不是则需要翻转一次,遍历完字符串,需要的翻转次数很明显可以得到。

code:

public static int getChangeTimes(String s1,String s2){
    int count = 0;
    for(int i=0;i<s1.length();i++){
        if(Math.abs(s1.charAt(i)-s2.charAt(i))==4||Math.abs(s1.charAt(i)-s2.charAt(i))==19){
        }else{
            count++;
        }
    }
    return count;
}
题目四:牛牛的好朋友羊羊在纸上写了n+1个整数,羊羊接着抹除掉了一个整数,给牛牛猜他抹除掉的数字是什么。牛牛知道羊羊写的整数神排序之后是一串连续的正整数,牛牛现在要猜出所有可能是抹除掉的整数。例如:10 7 12 8 11 那么抹除掉的整数只可能是9,5 6 7 8 那么抹除掉的整数可能是4也可能是9

输入描述:

输入包括2行:

第一行为整数n(1 <= n <= 50),即抹除一个数之后剩下的数字个数

第二行为n个整数num[i] (1 <= num[i] <= 1000000000)
输出描述:

在一行中输出所有可能是抹除掉的数,从小到大输出,用空格分割,行末无空格。如果没有可能的数,则输出mistake
思路:分析题目我们会发现只有n个数排序后像5,6,7,8或者5,6,8这样的数组才符合要求,我们把5 到6这种作为一次连续,显然满足条件的数组连续的次数一定是满足length-1或者length-2(length即数组的长度),需要注意当连续的次数为length-2时,它的左值要大于0.

code:

public static String getDeleteNumber(int[] arrays){
    Arrays.sort(arrays);
    int serialCounter =0;//数字连续的次数
    String deletedNumber = "";//返回值
    for(int i=1;i<arrays.length;i++){
        if(arrays[i-1]+1==arrays[i]){
            serialCounter++;
        }else{
            if(arrays[i-1]+2 ==arrays[i])
                deletedNumber+=arrays[i]-1;
        }
    }
    if(serialCounter==arrays.length-2){
        return deletedNumber;
    }else if(serialCounter==arrays.length-1){
        return (arrays[0]-1)>0?(arrays[0]-1)+" "+(arrays[arrays.length-1]+1):arrays[arrays.length-1]+1+"";
    }else{
        return "mistake";
    }
}
题目5:牛牛新买了一本算法书,算法书一共有n页,页码从1到n。牛牛于是想了一个算法题目:在这本算法书页码中0~9每个数字分别出现了多少次?

输入描述:

输入包括一个整数n(1 ≤ n ≤ 1,000,000,000)
输出描述:
输出包括一行10个整数,即0~9这些数字在页码中出现的次数,以空格分隔。行末无空格。

思路:显然最简单的是遍历所有的数字,然后对每个数字统计它含有的0-9的个数,但是时间复杂度为O(n),不符合题目时间限制。那么我们只能寻找规律,0-9我们发现每个数字出现的次数为1次,00-99每个数字出现的次数为20次,000-999每个数字出现的次数为300,其实不难发现,每个数字出现的次数为d*10^(d-1)(d就是当前数字的位数),但是我们应该注意,0的个数我们是多算了的,因为没有0页,01页,001页,所有我们需要去掉这些不合理的页码,我们发现0-9我们多算了一次0,00-99我们多算了10次0,000-999我们多算了100次0,不难发现,多算的0的个数满足10^(d-1)(d同样是数组的位数)。有了这些规律后,我们拿一个数字进行分析3567,显然我们可以这样分析,分成0000-0999,1000-1999,2000-2999,3000-3567,我们首先可以计算出从0到9每个数字有3*300次,然后又发现0,1,2,3每个数字需要再添加1000次,然后数字3得额外添加568次,接下来来我们就可以分析567了,567同样可以依此分析,然后是67,直到分析到7为止,(最后还需要把0多算的次数减去就可以了)其他数字也可以这么分析,就是一个不断递归计算的过程。

code:

public static int[] getEachDigitalSizes(int n){
    int[] digitals = new int[10];
    int[] b = new int[]{0,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
    int numberOfDigital = 0;
    int tempN = n;
    while (tempN>0){
        numberOfDigital++;
        tempN/=10;
    }
    int[] c =new int[numberOfDigital];//数组c里存储的是n的每一位
    tempN = n;
    int count = 0;
    while (tempN>0){
        c[count] = tempN%10;
        tempN/=10;
        count++;
    }
    for(int length=numberOfDigital;length>=1;length--){
        for(int i=0;i<=9;i++)digitals[i]+= c[length-1]*b[length-1]*(length-1);
        for(int i=0;i<c[length-1];i++)digitals[i]+=b[length];
        digitals[c[length-1]]+=n%b[length]+1;
    }
    for(int i=1;i<=numberOfDigital;i++){
        digitals[0]-=b[i];//减去多计算的0的个数
    }
    return digitals;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值