算法训练#9:思维题(1)

37 阅读3分钟

第一题

Anti-knapsack

内容理解

给出两个整数n和k,在一个1到n的整数集合中,需要解题者通过删除最少的数,来达到集合中没有任意一个子集中的数相加等于k的效果。

输入

整数t,表示输入的案例个数,1t1001\le t \le 100
整数n和k,其中1kn10001\le k\le n \le 1000

输出

输出t个案例的结果,每个结果格式如下

  1. 第一行输出一个整数,表示删除后的整个集合的长度(也就是含有多少个整数)
  2. 第二行输出若干个整数,表示删除后的集合中的所有元素
  3. 其中若对一种案例有多种结果,则输出一种即可

思路

对于这种题目,我们一般是想怎么样可以用一个比较万能的方法去删除,因为这里是子集中的数相加的和不呢为k,那我们不妨这样想:把那些足够小的数删掉不就可以了?那什么才叫足够小呢?我们用反向思维来想一下:找出一个子集,其中的数的和为k。若子集的长度为1,则数必须为k本身;若子集的长度为2,则有一个数小于k/2,另一个数大于k/2;若子集的长度更长,则数更多,更小的数也更多,值的分布有可能更不平均,但是我们可以找到一个共同点:按照这样的找法,子集长度大于等于2时,必然有小于k/2的数,而且把小于k/2的数全部删掉之后,剩余的数随便凑两个在一起都不等于k。

代码

import java.util.Scanner;
public class Anti_knapsack {
    public static void main(String args[])
    {
        int n=0;
        int k=0;
        //输入
        Scanner sc=new Scanner(System.in);
        count=sc.nextInt();
        for (int i=0;i<count;i++)
        {
            n=sc.nextInt();
            k=sc.nextInt();
            //直接判定删除后剩下的数
            if(n==k)
                System.out.println(k/2);
            else
                System.out.println(k/2+(n-k));
            for (int j=k/2;j<=n;j++){
                //这里就是判断应不应该输出k/2的部分,因为计算机的除法是直接取整,奇数k的k/2是能与k/2+1相加等于k的,而偶数k则不然
                if (k%2==0&&j<k)
                    System.out.print(j+" ");
                else if (j!=k&&j>k/2)
                    System.out.print(j+" ");
            }
            System.out.println();
        }
    }

}

第二题

Split it!

内容理解

给出一个字符串s和一个数字k,要求判定s是否由2k+1个非空字符串以回文的形式组成(其中第1个到第k个拼接起来后,第k+1个可以是任何字符串,但是后面的k个字符串分别是第k到第1个的反转字符串)

输入

整数t,表示输入的案例个数,1t1001\le t \le 100
整数nkn表示字符串长度,其中1n100,0kn21\le n\le 100,0\le k \le \frac{n}{2}

输出

输出t行结果,每行格式:YES代表是,NO代表否

思路

想要找出k+1个非空字符串容易误解为:要从哪里分割?这样的分割方式会不会有问题?其实我们大可不必这样,题目要求找这么多,可没要求那k个字符串的长度,我们直接定为1不就可以了?完全没必要理会中间那第k+1个字符嘛!这样就转化为一个非常简单的判定问题了,只靠双指针循环遍历就可以解决

import java.util.Scanner;
public class Split_it {
    public static void main(String args[])
    {
        Scanner sc=new Scanner(System.in);
        //输入
        int t;
        t=sc.nextInt();
        int n=0,k=0;
        for(int i=0;i<t;i++)
        {
            int yes=1;
            n=sc.nextInt();
            k=sc.nextInt();
            String s=sc.next();
            //双指针判定
            for(int j=0;j<k;j++)
            {
                char left=s.charAt(j);
                char right=s.charAt(n-j-1);
                if(left!=right||s.length()<=2*k) {//若不相等,或者字符串的长度不符合要求(连2k+1个字符串都没有)
                    yes = 0;
                    break;
                }
            }
            if(yes==1)
            {
                System.out.println("yes");
            }
            else{
                System.out.println("no");
            }
        }
    }
}

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 12 天,点击查看活动详情