字节跳动5.11 开发笔试题

时间:2020-05-11 岗位:开发(2020字节跳动校园招聘后端和客户端方向第三场考试)

文章目录

    • T1、操作字符串
      • 思路:栈记录之前状态
    • T2、计算字符串解释方法数
      • 思路一:回溯
      • 思路二:动态规划
    • T3、最小染袜子个数?
      • 思路:并查集
    • T4、区间内的不同字符个数
      • 思路:暴力模拟(超时)

T1、操作字符串

4种操作:(1)增加;(2)删除;(3)输出;(4)回退;
(4)回退操作只对(1)(2)起作用;

思路:栈记录之前状态

StringBuilder 记录字符串,然后每次进行(1)/(2)操作就放入栈中;在(4)操作的时候将字符串更新为栈顶字符串;

package compitition.zijie;

import java.util.Scanner;
import java.util.Stack;

public class Main1{
    public static void main(String[] args){
        Scanner c = new Scanner(System.in);
        int n = c.nextInt();
        StringBuilder sb = new StringBuilder();
        Stack<String> stack = new Stack<>();
        while (n-- > 0) {
            switch (c.nextInt()){
                case 1 :
                    stack.push(sb.toString());
                    String s = c.next();
                    sb.append(s);
                    break;
                case 2 :
                    stack.push(sb.toString());
                    int del = c.nextInt();
                    if(sb.length() < del){
                        sb = new StringBuilder();
                    }else{
                        sb.delete(sb.length()-del,sb.length());
                    }
                    break;
                case 3 :
                    int print = c.nextInt();
                    System.out.println(sb.charAt(print-1));
                    break;
                case 4 :
                    sb = new StringBuilder(stack.pop());
                    break;
            }

        }
        c.close();
    }
}

T2、计算字符串解释方法数

给定字符串s和字典;问字符串有几种解释方式;
字典中至少存在两个单词,且每个单词长度<20;

思路一:回溯

用Set装入字典,maxLen记录单词最大长度;
递归寻找从索引begin开始往后的maxLen长度的字符串是否在字典中,是则继续递归;
【数组越界错误!!!】(不知道为什么)

思路二:动态规划

Set装入字典;dp状态:以i结尾的字符串的解释方法数目;
如果在[index-maxLen , index]区间找到有单词在字典中,则更新当前dp[index]
转移方程:
如果Set包含s.substring(index+1-nowLen,index+1),则dp[index] += dp[index+1-nowLen-1];

package compitition.zijie;
// 【T2】回溯
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Main2{
    static long result = 0;
    static int len = 0;
    static int maxLen = 0;

    public static void main(String[] args){
        Scanner c = new Scanner(System.in);
        String s = c.next();
        len = s.length();

        Set<String> set = new HashSet<>();
        int n = c.nextInt();
        while (n-- > 0){
            String ss = c.next();
            set.add(ss);
            maxLen = Math.max(maxLen,ss.length());
        }
        c.close();
        backtrack(s,0,set);
        System.out.println(result);
    }

    private static void backtrack(String s, int begin,Set<String> set){
        if(begin >= len){
            result++;
            result = result % 835672545;
            return;
        }

        int nowLen = 1;
        while(begin+nowLen <= len && nowLen <= maxLen){
            String nowStr = s.substring(begin,begin+nowLen);
            if(set.contains(nowStr)){
                backtrack(s,begin+nowLen,set);
            }
            nowLen++;
        }

    }
}

package compitition.zijie;
//【T2】dp
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Main2_2{
    static int len = 0;
    static int maxLen = 0;

    public static void main(String[] args){
        Scanner c = new Scanner(System.in);
        String s = c.next();
        len = s.length();
        long[] dp = new long[len];
        Set<String> set = new HashSet<>();
        int n = c.nextInt();
        while (n-- > 0){
            String ss = c.next();
            set.add(ss);
            maxLen = Math.max(maxLen,ss.length());
        }
        c.close();
        dp[0] = set.contains(s.substring(0,1))?1:0;

        int index = 1;
        while(index < len){
            int nowLen = 1;
            while(nowLen <= maxLen && index+1-nowLen >= 0){
                String nowStr = s.substring(index+1-nowLen,index+1);
                if(set.contains(nowStr)){
                    if(index+1-nowLen == 0){
                        dp[index]++;
                    }else{
                        dp[index] += dp[index+1-nowLen-1];
                    }
                    dp[index] = dp[index] % 835672545;
                }
                nowLen++;
            }
            index++;
        }
        System.out.println(dp[len-1] % 835672545);
    }

}

T3、最小染袜子个数?

给出n只袜子的颜色;给出m天,每天要穿的两只袜子的索引;求满足每天两只袜子同色时,最小的改变袜子颜色次数(染袜子次数);

思路:并查集

并查集合并n个索引,分类成len个集合;对每个集合,求集合的元素个数(总袜子数量)和已有的最大单个颜色数目(该集合中不需要染色的袜子个数);

package compitition.zijie;

import java.util.*;

public class Main3{
    public static void main(String[] args){
        Scanner c = new Scanner(System.in);
        int n = c.nextInt();
        int m = c.nextInt();
        int[] nums = new int[n];
        for(int i=0;i<n;i++){
            nums[i] = c.nextInt();
        }
        //一共有n个袜子
        UnionFindSet uset = new UnionFindSet(n);
        //将n个袜子合并
        while (m-- > 0){
            int a_i = c.nextInt()-1;
            int b_i = c.nextInt()-1;
            //这两个序号的袜子是要变成一个颜色哦
            uset.union(a_i,b_i);
        }
        c.close();


        List<List<Integer>> listAll = uset.fenzu();
        int result = 0;
        for(List<Integer> list : listAll){
            int max = 0;
            Map<Integer,Integer> map = new HashMap<>();
            for(int index : list){
                int nowNums = map.getOrDefault(nums[index],0)+1;
                map.put(nums[index],nowNums);
                max = Math.max(max,nowNums);
            }
            result += list.size() - max;
        }
        System.out.println(result);
    }
}
class UnionFindSet {

    int[] parents;//存放父节点下标
    int[] ranks;//表示当前的秩(深度)
    int len;

    //初始化一个n大小的并查集结构
    public UnionFindSet(int n) {
        len = n;
        parents = new int[n];
        for (int i = 0; i < n; i++) {
            parents[i] = i;
        }
        ranks = new int[n];
    }

    //优化1
    //查找当前节点的父亲,与此同时有【路径压缩】优化
    public int find(int x) {
        if (x != parents[x]) {//如果x不是父节点
            parents[x] = find(parents[x]);//那么它的父节点就是根节点
        }
        return parents[x];
    }


    //合并两个节点,以其中一个节点作为父亲,包含【按秩合并】优化
    public void union(int x, int y) {
        x = find(x);//找x的父节点
        y = find(y);
        if (x == y) return;
        //直接合并两个父节点
        if (ranks[x] > ranks[y]) {
            parents[y] = x;
        } else if (ranks[x] < ranks[y]) {
            parents[x] = y;
        } else {
            parents[x] = y;
            ranks[y]++;
        }
    }

    //返回所有的分组,只有root节点对应的list才不为空
    public List<List<Integer>> fenzu() {
        List<List<Integer>> result = new ArrayList<>();
        for (int i = 0; i < len; i++) {
            result.add(new ArrayList<>());//增加n个list
        }
        for (int i = 0; i < len; i++) {
            result.get(find(i)).add(i);//根节点的那个list加上i
        }
        return result;
    }
}

T4、区间内的不同字符个数

给一个字符串s,有两种操作(1)改变s[i]字符为c;(2)查询[left , right]中不同字符的个数;

思路:暴力模拟(超时)

package compitition.zijie;


import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;


public class Main4{


    public static void main(String[] args){
        Scanner c = new Scanner(System.in);
        char[] str = c.next().toCharArray();
        //System.out.println(Arrays.toString(dp));
        int n = c.nextInt();
        while(n-->0){
            int caozuo = c.nextInt();
            switch (caozuo){
                case 1 ://变换
                    int index = c.nextInt()-1;
                    String newChar = c.next();
                    str[index] = newChar.charAt(0);
                    break;

                case 2 ://查询
                    int begin = c.nextInt()-1;
                    int end = c.nextInt()-1;
                    int result = 0;
                    Set<Character> set = new HashSet<>();
                    for(int i=begin;i<=end;i++){
                        set.add(str[i]);
                    }
                    System.out.println(set.size());
                    break;
            }
        }
        c.close();
    }

}

你可能感兴趣的:(笔试)