4.20 bilibili笔试 JAVA

第一题  找牛牛

青牛小学一年一度的六一儿童节开始了。现在牛牛们围成一圈坐在草地上,为了方便,我们把牛牛们编号为牛1,牛2,牛3,牛n。

其中牛1与牛2相邻,牛2与牛3相邻,牛n和牛1相邻。

为了更好的安排接下来的活动,牛老师很好奇:从这些牛中选出几只相邻的牛,总共有多少种不同的方案?

我们认为两个方案不同,当且仅当两种选法选出的牛个数不同或选出的牛的编号不完全相同

输入描述

输入一个整数n,表示牛的个数

输出描述

输出一个整数n,表示方案数

示例1

输入

2

输出

3

解释

环为1,2可以选择(1},{2},{1.2}

示例2

输入

4

输出

13

解释

环为1,2,3,4可以选择(1}, {2, {3}, {4},{1,2}, {2,3}, {3, 4}, {4, 1},{1,2,3},{2,3,4},{3,4,1} {4,1,2}{1,2,3,4}共13种情况

思路与代码

基本思路:观察问题,我们需要计算从n头牛中选出若干头相邻的牛的方案数。由于牛是围成一圈的,这意味着我们可以从任意一头牛开始数。

分解问题

  • 不特殊的方案:首先考虑所有的牛都不同时被选中的情况。在这种情况下,我们可以选择任意一头牛作为起点(有n种选择),然后选择从这头牛开始的任意连续数量的牛(1到n-1种选择,因为如果选择了n头,那就是特殊情况了)。因此,这部分的方案数为 (n *(n-1)。
  • 特殊方案:所有的牛都被选中的情况。这是一个特殊的方案,因为不管从哪头牛开始数,选出的都是全部的牛。这种情况下只有1种方案。

总结方案数:将上述两种情况相加,得到的总方案数就是 n*(n-1)+1。

因此代码将n*(n-1)+1直接输出就可以了。

如果增加难度,要求输出各个方案,则代码如下:

// 自己写的,比较复杂
import java.util.*;
public class zhao_niu {
    public List<List<Integer>> xianglin(int n) {
        List<List<Integer>> result = new ArrayList<>();
        int[] nums = new int[2*n-2];
        for (int i = 0; i < n; i++) nums[i] = i + 1;
        for (int i = 0; i < n-2; i++) nums[n+i] = nums[i];

        for (int j = 0; j < n; j++){
            result.add(new ArrayList<>());
            for (int i = 0; i < n - 1; i++) {
                List<Integer> list = new ArrayList<>(result.get(j*n+i));
                list.add(nums[j+i]);
                result.add(list);
            }
        }
        for (int i = 0; i < n; i++){
            result.remove(i*(n-1));
        }

        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < n; i++){
            list.add(nums[i]);
        }
        result.add(list);
        return result;
    }

    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        zhao_niu obj = new zhao_niu();
        List<List<Integer>> result = obj.xianglin(n);
        for (int i = 0; i < result.size(); i++){
            System.out.println(result.get(i));
        }
        // System.out.println(n*(n-1) + 1);
    }
}
// 别人写的
import java.util.*;

public class zhao_niu2 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt(); // 输入小孩的个数

        // 输出各个方案
        List<List<Integer>> schemes = findSchemes(n);
        for (List<Integer> scheme : schemes) {
            System.out.println(scheme);
        }
    }

    // 寻找所有方案的方法
    public static List<List<Integer>> findSchemes(int n) {
        // 存储所有方案的列表
        List<List<Integer>> schemes = new ArrayList<>();

        // 遍历每个小孩,生成单独的方案
        for (int i = 1; i <= n; i++) {
            List<Integer> scheme = new ArrayList<>();
            scheme.add(i);
            schemes.add(scheme);
        }

        // 逐步增加小孩数量,生成更长的方案
        for (int len = 2; len <= n-1; len++) {
            // 从每个小孩开始,生成具有特定长度的方案
            for (int start = 1; start <= n; start++) {
                List<Integer> scheme = new ArrayList<>();
                // 构建方案中的小孩编号
                for (int j = start; j < start + len; j++) {
                    int num = j > n ? j - n : j; // 处理小孩编号循环的情况
                    scheme.add(num);
                }
                // 将生成的方案加入方案列表
                schemes.add(scheme);
            }
        }

        List<Integer> scheme = new ArrayList<>();
        for (int i = 1; i <= n; i++){
            scheme.add(i);
        }
        schemes.add(scheme);
        // 返回所有生成的方案列表
        return schemes;
    }
}

 

第二题 翻转字符串

给出一个长度为n的字符串s和一个整数k,现在请你依次按照i= 1,2,.....n-k+1的顺序求出以下操作得到的字符串将字符串s的第i个字符至第i+k- 1之间的所有字符翻转。 求出最终状态的字符串。 例如:n是5,是3,s是"hello"。 i=1时,翻转[1,3]之间的字符,得到"lehlo" i=2时,翻转 [2,4]之间的字符,得到"llheo" i=3时,翻转 [3,5]之间的字符,得到"lloeh" 因此,最终的s为"lloeh"。

输入描述

第一行输入正整数n,k。

第二行输入仅由小写字母构成的字符串s。 2≤k≤n≤2x10^5

输出描述

输出s经过翻转后的最终状态。

示例1

输入

5 3

hello

输出

lloeh

示例2

输入

8 5

nowcoder

输出

odernowc

思路与代码

跟上一题类似,需要想象一下这个过程,从第k个字符被翻转,更多是逻辑吧,思路如下:

  1. 操作次数:首先,注意到对于每个 i 从 1 到 n-k+1,我们会进行 n-k+1 次翻转操作。
  2. 奇偶性分析:对于任何给定的一段长度,连续两次完全相同的翻转将会抵消,即字符序列会恢复到翻转前的状态。因此,如果一个字符被翻转奇数次,它的最终位置会与初始位置不同;如果被翻转偶数次,它的最终位置会与初始位置相同。
  3. 翻转的影响范围:在这个问题中,每次翻转的影响范围是固定长度的(k个字符),并且随着 i 的递增,这个翻转窗口在字符串上滑动。
  4. 特定位置的翻转次数
    • 对于字符串 s 的前 k-1 个字符和后 k-1 个字符,随着翻转窗口的滑动,它们的翻转次数会从 1 逐渐增加到 k,然后再逐渐减少到 1。这意味着,如果 n-k 是奇数,则这部分字符的翻转次数为奇数;如果 n-k 是偶数,则翻转次数为偶数。
    • 对于字符串的其余部分,即从第 k 个字符到第 n-k 个字符,每个字符会被翻转 k 次,这是一个固定的偶数次。

暴力解法只能过30%。

import java.util.*;
public class fan_zhuan {
    public String reverse_string(int n, int k, String s){
        char[] ch = s.toCharArray();
        int left = 0;
        int right = n - k;
        for (int i = 0; i < n - k + 1; i++){
            reverse(ch, i, i+k-1);
        }
        return new String(ch);
    }

    public void reverse(char[] ch, int start, int end){
        for (; start < end; start++, end--){
            char tmp = ch[start];
            ch[start] = ch[end];
            ch[end] = tmp;
        }
    }

    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int k = in.nextInt();
        in.nextLine();
        String s = in.nextLine();
        fan_zhuan obj = new fan_zhuan();
        String after = obj.reverse_string(n, k, s);
        System.out.println(after);
    }
}

 找规律的解法:

import java.util.Scanner;

public class fanzhuan3 {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        scanner.nextLine(); // Consume the newline character after reading integer input
        String s = scanner.nextLine();
        if ((n - k) % 2 != 0) {
            System.out.println(s.substring(k - 1) + s.substring(0, k - 1));
        } else {
            StringBuilder reversedSubstring = new StringBuilder(s.substring(0, k - 1));
            System.out.println(s.substring(k - 1) + reversedSubstring.reverse().toString());
        }
        scanner.close();
    }
}

 

posted @ 2024-04-28 14:09  实数集  阅读(151)  评论(0)    收藏  举报