栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

B站左程云算法视频中级班9~10

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

B站左程云算法视频中级班9~10

题目1:给定一个整数数组,长度为n,找到[1,n]中所有未出现在A中的数

inplace算法:使得i位置上放i+1

3 2 1 6 2 7 5

0 1 2 3 4 5 6

0位置放1,所以3和2位置的数换,1位置放2,2位置放3,.....

//请保证arr[0..N-1]上的数字都在[1~n]之间
public static void printNumberNoInArray(int[] arr) {
    if (arr == null || arr.length == 0){
        return ;
    }
    for (int value : arr){ // 争取做到,i位置上,放的数是 i + 1
        modify(value,arr);
    }
    for(int i = 0; i < arr.length; i++){
        if (arr[i] != i + 1){// 没做到的位置,就知道缺的数字
            System.out.println(i + 1);
        }
    }
}

public static void modify(int value, int[] arr){
    while(arr[value - 1] != value){
        int tmp = arr[value - 1];
        arr[value - 1] = value;
        value = tmp; 
    }
}

题目2:(主播打赏问题) 初始人气值a(设为偶数),目标人气值b(偶数)  a小于等于b

方案1)点赞,花费x, 人气值+2 

        2)送礼 ,花费Y,人气值*2

        3)私聊,花费Z,人气值-2

使得a = b,至少花费几个币

//想要达到的目标是end
//目前达到的分数是cur
//三种决策
//1) cur + 2
//2) cur * 2
//3) cur - 2
public static int func(int x, int y, int z, int end, int cur){
    if(cur == end){
        return 0;
    }
    int p1 = process(x, y, z, end, cur + 2) + x;
    int p2 = process(x, y, z, end, cur * 2) + y;
    int p3 = process(x, y, z, end, cur - 2) + z;
    return Math.min(p1, Math.min(p2, p3));
}

存在的问题:递归跑不完

缺少限制条件,basecase的量不够

1)求出频繁解,设通过一直点赞得答案,花费x币,所以添加设置,当花费超过x时return(通用)

2)通过存在a>b,再减,例如a*2 - 2 = b,则a不能超过目标的两倍

public static int minCoins1(int add, int times, int del, int start, int end){
    if (start > end){
        return -1;
    }
    return process(0, end, add, times, del, start, end * 2, ((end - start) / 2) * add);
}

//preMoney 之前花了多少币  可变
//aim 目标 
//int add, int times, int del  固定
//start当前来到的人气
//limitAim人气达到什么程度不需要再尝试 固定
//limitCoin已经使用的币大到什么程度不需要再尝试了 固定
//返回最小币数
public static int process(int preMoney, int aim, int add, int times, int del, int start, int limitAim, int limitCoin){
   if (preMoney > limitCoin){
        return Integer.MAX_VALUE;
    }
    if (start < 0){
        return Integer.MAX_VALUE;
    }
    if (start > limitAim){
        return Integer.MAX_VALUE;
    }
    if (aim == start){
        return preMoney;
    }
    int min = Integer.MAX_VALUE;
    //人气+2的方式
    int p1 = process(preMoney + add, aim, add, times, del, start + 2, limtiAim, limitCoin);
    if(p1 != Integer.MAX_VALUE){
        min = p1;
    }
    //人气-2的方式
    int p2 = process(preMoney + add, aim, add, times, del, start - 2, limtiAim, limitCoin);
    if(p2 != Integer.MAX_VALUE){
        min = Math.min(min, p2);
    }
    //人气*2的方式
    int p3 = process(preMoney + add, aim, add, times, del, start * 2, limtiAim, limitCoin);
    if(p3 != Integer.MAX_VALUE){
        min = Math.min(min, p3);
    }
    return min;
}

题目3:每个活动需要花费一定的时间参与,参与活动可以从任意活动开始,但一旦开始,就需要将后续活动参加完毕,活动之间存在依赖,计算在有限时间内能获得的最大奖励和需要的最少时长

思路:建表map(有序表)key总天数,value钱

每个节点里的表天数变大,收益也变大,最后合成一个大表

 

题目4:给一个只有0(假)、1(真)、&(与)、|(或)和^(异或)五种字符组成的字符串express,给再一个布尔值desired,返回express有多少种组合方式(加小括号),可以达到desired的结果

0        &        1        ^        0        |        0        &        1

0        1        2        3        4        5        6        7        8

1) &         2)^         3 )|         4)&  做最后结合的符号         

public static int num1(String express, boolean desired){
    if(express == null || express.equals("")){
        return 0;
    }
    char[] exp = express.toCharArray();
    if (!isValid(exp)){
        return 0;
    }
    return p(exp, desired, 0, exp.length - 1);
}

//exp[L..R] 返回期待为desired的组合方法数
//潜台词:L R一定不要压中逻辑符号
public static int p(char[] exp, boolean desired, int L, int R){
    if (L == R){//basecase 1
        if(exp[L] == '1'){
            return desried ? 1 : 0;
        }else {
            return desried ? 0 : 1;
        }
    }
    
    // L..R
    int res = 0;    
    if(desired){
        //i位置尝试L..R范围上的每一个逻辑符号,都是最后结合的
        for (int i = L + 1; i < R; i += 2) {
            switch(exp[i]){
                case '&':
                    res += p(exp, true, L, i - 1) * p(exp, true, i + 1, R);
                    break;
                case '|':
                    res += p(exp, true, L, i - 1) * p(exp, true, i + 1, R);
                    res += p(exp, false, L, i - 1) * p(exp, true, i + 1, R);
                    res += p(exp, true, L, i - 1) * p(exp, false, i + 1, R);
                    break;
                case '^':
                    res += p(exp, false, L, i - 1) * p(exp, true, i + 1, R);
                    res += p(exp, true, L, i - 1) * p(exp, false, i + 1, R);
                    break;
            }
        }
    }else {//期待为false
       for (int i = L + 1; i < R; i += 2) {
            switch(exp[i]){
                case '&':
                    res += p(exp, false, L, i - 1) * p(exp, false, i + 1, R);
                    res += p(exp, false, L, i - 1) * p(exp, true, i + 1, R);
                    res += p(exp, true, L, i - 1) * p(exp, false, i + 1, R);
                    break;
                case '|':
                    res += p(exp, false, L, i - 1) * p(exp, false, i + 1, R);
                    break;
                case '^':
                    res += p(exp, true, L, i - 1) * p(exp, true, i + 1, R);
                    res += p(exp, false, L, i - 1) * p(exp, false, i + 1, R);
                    break;
            }
        }
    }
    return res;
}

public static boolean isValid(char[] exp){
    if((exp.length & 1) == 0){
        return false;
    }
    for(int i = 0; i < exp.length; i += 2){
        if((exp[i] != '1') && (exp[i] != '0')){
            return false;
        }
    }
    for(int i = 1; i < exp.length; i += 2){
        if((exp[i] != '&') && (exp[i] != '|') && (exp[i] != '|')){
            return false;
        }
    }
    return true;
}

动态规划:

public static int dpLive(String express, boolean desired){
    char[] str = express.toCharArray();
    int N = str.length;
    int[][] tMap = new int[N][N];
    int[][] fMap = new int[N][N];
    for(int i = 0; i < N; i += 2){
        tMap[i][i] = str[i] == '1' ? 1 : 0;
        fMap[i][i] = str[i] == '0' ? 1 : 0;
    }
    for (int row = N - 3; row >= 0; row -= 2){
        for (int col = row + 2; col < N; col += 2){
            //row...col tMap fMap
            for(int i = row + 1; i < col; i += 2){
                switch(str[i]){
                case '&':
                    tMap[row][col] += tMap[row][i - 1] * tMap[i + 1][col];
                    break;
                case '|':
                    tMap[row][col] += tMap[row][i - 1] * fMap[i + 1][col];
                    tMap[row][col] += fMap[row][i - 1] * tMap[i + 1][col];
                    tMap[row][col] += tMap[row][i - 1] * tMap[i + 1][col];
                    break;
                case '^':
                    tMap[row][col] += fMap[row][i - 1] * tMap[i + 1][col];
                    tMap[row][col] += tMap[row][i - 1] * fMap[i + 1][col];
                    break;
            }
                switch(str[i]){
                case '&':
                    fMap[row][col] += fMap[row][i - 1] * tMap[i + 1][col];
                    fMap[row][col] += tMap[row][i - 1] * fMap[i + 1][col];
                    fMap[row][col] += fMap[row][i - 1] * fMap[i + 1][col];
                    break;
                case '|':
                    fMap[row][col] += fMap[row][i - 1] * fMap[i + 1][col];
                    break;
                case '^':
                    fMap[row][col] += tMap[row][i - 1] * tMap[i + 1][col];
                    fMap[row][col] += fMap[row][i - 1] * fMap[i + 1][col];
                    break;
            }
        }
    }
    return desired ? tMap[0][N - 1] : fMap[0][N - 1];
}

题目5:在一个字符串中找到没有重复字符串中最长的长度

思路:看到子串和子序列就想到以i位置为结尾的情况下最长无重复子序列的情况

两种情况:i位置的数的第一个瓶颈:上次i位置数出现的位置

                i-1结尾的最长无重复子串的长度是多少 ,以i结尾突破不了i-1的瓶颈

       两个瓶颈哪个近,哪个就是答案

 

public static int maxUnique(String str){
    if(str == null || str.equals("")){
        return 0;
    }
    char[] chas = str.toCharArray();
    //map代替了哈希表 假设字符的码是0~255
    int[] map = new int[256];
    for(int i = 0; i < 256; i++){
        map[i] = -1;
    }
    int len = 0;
    int pre = -1;
    int cur = 0;
    for (int i = 0; i != chas.length; i++){
        pre = Math.max(pre, map[chas[i]]);
        cur = i - pre;
        len = Math.max(len, cur);
        map[chas[i]] = i;
    }
    return len;
}

题目6:编辑距离问题

给定两个字符串str1和str2,再给定三个整数ic、dc和rc代表插入、删除和替换一个字符的代价,返回将str1编辑成str2的最小代价

1)1:a1bck   2: abc

将a1bc转成abc,然后删去k  dp[i-1][j]+del

2)1:abcd   2:abcde    

       dp[i][j-1] + add

3)1:abcds   2:abcdt

        dp[i - 1][j -1] + replace

4)abcde   abcde

         dp[i - 1][j -1]

public static int minCost1(String str1, String str2, int ic, int dc, int rc){
    if (str1 == null || str2 == null){
        return 0;
    }
    char[] chs1 = str1.toCharArray();
    char[] chs2 = str2.toCharArray();
    int row = chs1.length + 1;
    int col = chs2.length + 1;
    int[][] dp = new int[row][col];
    for (int i = 1; i < row; i++){
        dp[i][0] = dc * i;
    }
    for (int i = 1; i < row; i++){
        for (int j = 1; i < col; j++){
            if(chs1[i - 1] == chs2[j - 1]){
                dp[i][j] = dp[i -1][j - 1];
            }else{
                dp[i][j] = dp[i - 1][j - 1] + rc;
            }
            dp[i][j] = Math.min(dp[i][j], dp[i][j - 1] + ic);
            dp[i][j] = Math.min(dp[i][j], dp[i - 1][j] + dc);
        }
    }
    return dp[row - 1][col - 1];
}

题目7:给一个全是小写字母的字符串,删除多余字符,每种字符保留一个,并让字典序最小

建立词频表,选acs码最小的保留

public static String romove(String str){
    if(str == null || str.length() < 2){
        return str;
    }
    int[] map = new int[256];
    for(int i = 0; i < str.length(); i++){
        map[str.charAt(i)]++;
    }
    int minACSIndex = 0;
    for(int i = 0; i < str.length(); i++){
        if(--map[str.charAt(i)] == 0){
            break;
        }else{
            minACSIndex = str.charAt(minACSIndex) > str.charAt(i) ? i : minACSIndex;
        }
    }
    return String.valueOf(str.charAt(minACSIndex)) + remove(str.substring(minACSIndex + 1).replaceAll(String.valueOf(str.charAt(minACSIndex)),""));
}

题目8:a,b,c,d,e,f,……,z

1){a}

2){b}

……

26){z}

27){ab}

……

{az}

{bc}

给一个子序列,返回第几个

思路:写两个函数f和g

f(N)长度为N的子序列有多少个 g(char,len)以char开头的长度为len的子序列有多少个

//必须以i号字符开头、长度为len的子序列有多少个
public static int g(int i, int len){
    int sum = 0;
    if(len == 1){
        return 1;
    }
    for(int j = i + 1; j <= 26; j++){
        sum += g(j, len - 1);
    }
    return sum;
}

//长度为len的字符串有多少个
public static int f(int len){
    int sum = 0;
    for (int i = 1; i <= 26; i++){
        sum += g(i, len);
    }
    return sum;
}
public static int kth(String s){
    char[] str = s.toCharArray();
    int sum = 0;
    int len = str.length;
    for(int i = 1; i < len; i++){
        sum += f(i);
    }
    int first = str[0] - 'a' + 1;// 第一个字符
    for (int i = 1; i < first; i++){
        sum += g(i, len);
    }
    int pre = first;
    for(int i = 1; i < len; i++){
        int cur = str[i] - 'a' + 1;
        for(int j = pre + 1; j < cur; j++){
            sum += g(j, len - i);
        }
        pre = cur;
    }
    return sum + 1;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/973497.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号