【算法刷题】Day25

1. 粉刷房子

在这里插入图片描述
原题链接


题干:

每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色
花费是以一个 n x 3 的正整数矩阵 costs
costs[0][0] 表示第 0 号房子粉刷成红色的成本花费
在这里插入图片描述


算法原理:

1. 状态表示:

dp[i][0] 表示:粉刷到 i 位置的时候,最后⼀个位置粉刷上「红色」,此时的最小花费

dp[i][1] 表示:粉刷到 i 位置的时候,最后⼀个位置粉刷上「蓝色」,此时的最小花费

dp[i][0] 表示:粉刷到 i 位置的时候,最后⼀个位置粉刷上「绿色」,此时的最小花费

2. 状态转移方程

在这里插入图片描述
dp[i][0] = min(dp[i - 1][1], dp[i- 1][2]) + costs[i - 1][0]
dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1]
dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2]

3. 初始化

在这里插入图片描述

  1. 辅助结点里面的值要「保证后续填表是正确的」
  2. 「下标的映射关系」

4. 填表顺序

从左往右,三个表⼀起填

5. 返回值

min(dp[n][0], min(dp[n][1], dp[n][2]))


代码:

class Solution {
    public int minCost(int[][] costs) {
        int n = costs.length;
        int[][] dp = new int[n + 1][3];
        for(int i = 1; i <= n; i++) {
            dp[i][0] = Math.min(dp[i - 1][1], dp[i - 1][2]) + costs[i - 1][0];
            dp[i][1] = Math.min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1];
            dp[i][2] = Math.min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2];
        }
        return Math.min(dp[n][0], Math.min(dp[n][1], dp[n][2]));
    }
}

在这里插入图片描述


2. 判定字符是否唯一

在这里插入图片描述
原题链接


题干:

确定一个字符串 s 的所有字符是否全都不同


算法原理:

1. 哈希表

时间复杂度为 O(n)
空间复杂度为 O(n)
直接创建一个大小为 26 的 hash 表就可以了

2. 位图思想

每⼀个「比特位」代表⼀个「字符」,⼀个 int 类型的变量的 32 位足够表示所有的小写字⺟
比特位里面如果是 0 ,表示这个字符没有出现过
比特位里面的值是 1 ,表示该字符出现过

优化点:
运用“鸽巢原理”
len > 26 说明一定有重复的字符


代码:

class Solution {
    public boolean isUnique(String astr) {
        if(astr.length() > 26) {
            return false;
        }
        int map = 0;
        for(int i = 0; i < astr.length(); i++) {
            int x = astr.charAt(i) - 'a';
            if(((map >> x) & 1) == 1) {
                return false;
            }
            map |= (1 << x);
        }
        return true;
    }
}

在这里插入图片描述


3. 丢失的数字

在这里插入图片描述
原题链接


题干:

包含 [0, n] 中 n 个数的数组 nums
找出 [0, n] 这个范围内没有出现在数组中的那个数


算法原理:

1. 哈希表

两次遍历
在这里插入图片描述

2. 高斯求和

在这里插入图片描述

3. 位运算(异或)

在这里插入图片描述


代码:

class Solution {
    public int missingNumber(int[] nums) {
        int ret = 0;
        for(int i = 0; i < nums.length; i++) {
            ret ^= nums[i];
        }
        for(int i = 0; i <= nums.length; i++) {
            ret ^= i;
        }
        return ret;
    }
}

在这里插入图片描述


4. 只出现一次的数字 II

在这里插入图片描述
原题链接


题干:

一个整数数组 nums
除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
找出并返回那个只出现了一次的元素


算法原理:

在这里插入图片描述
每一个数的 比特位 可能出现四种情况
我们通过 ret 的每⼀个比特位上的值,就可以将 ret 给还原出来


代码:

class Solution {
    public int singleNumber(int[] nums) {
        int ret = 0;
        for(int i = 0; i < 32; i++) {
            int sum = 0;
            for(int x : nums) {//统计 sum 中所有的数的第 i 位的和
                if(((x >> i) & 1) == 1) {
                    sum++;
                }
            }
            sum %= 3;
            if(sum == 1) {
                ret |= 1 << i;
            }
        }
        return ret;
    }
}

在这里插入图片描述


5. 消失的两个数字

在这里插入图片描述
原题链接


题干:

定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字
任意顺序返回这两个数字


算法原理:(位运算)

在这里插入图片描述

  1. 将所有的数异或在一起,tmp
    tmp = a ^ b

  2. 找到 tmp 中,比特位上为 1 的那一位
    在这里插入图片描述

  3. 根据 x 为的不同,划分为两类异或


代码:

class Solution {
    public int[] missingTwo(int[] nums) {
        //1. 先把所有的数异或在一起
        int tmp = 0;
        for(int x : nums) {
            tmp ^= x;
        }
        for(int i = 1; i <= nums.length + 2; i++) {
            tmp ^= i;
        }

        //2. 找出 a, b 两个数比特位不同的哪一位
        int diff = 0;
        while(true) {
            if(((tmp >> diff) & 1) == 1) {
                break;
            }else {
                diff++;
            }
        }

        //3. 将所有的数按照 diff 位不同,分两类异或
        int[] ret = new int[2];
         for(int x : nums) {
            if(((x >> diff) & 1) == 1) {
                ret[1] ^= x;
            }else {
                ret[0] ^= x;
            }
        }
        for(int i = 1; i <= nums.length + 2; i++) {
            if(((i >> diff) & 1) == 1) {
                ret[1] ^= i;
            }else {
                ret[0] ^= i;
            }
        }
        return ret;
    }
}

在这里插入图片描述


  • 19
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柒柒要开心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值