第二十八天

练习

统计字典序元音字符串的数目

给你一个整数 n,请返回长度为 n 、仅由元音 (a, e, i, o, u) 组成且按 字典序排列 的字符串数量。

字符串 s 按 字典序排列 需要满足:对于所有有效的 i,s[i] 在字母表中的位置总是与 s[i+1] 相同或在 s[i+1] 之前。

 

示例 1:

输入:n = 1
输出:5
解释:仅由元音组成的 5 个字典序字符串为 ["a","e","i","o","u"]
示例 2:

输入:n = 2
输出:15
解释:仅由元音组成的 15 个字典序字符串为
["aa","ae","ai","ao","au","ee","ei","eo","eu","ii","io","iu","oo","ou","uu"]
注意,"ea" 不是符合题意的字符串,因为 'e' 在字母表中的位置比 'a' 靠后
示例 3:

输入:n = 33
输出:66045
 

提示:

1 <= n <= 50 
class Solution {
    public int countVowelStrings(int n) {
      return (n+4)*(n+3)*(n+2)*(n+1)/(4 * 3 * 2 *1);
    }
}
class Solution {
    private Integer[][] f;
    private int n;

    public int countVowelStrings(int n) {
        this.n = n;
        f = new Integer[n][5];
        return dfs(0, 0);
    }

    private int dfs(int i, int j) {//回溯
        if (i >= n) {//直到最后i>=n的时候,只剩下一种情况了
            return 1;//最后的值就是1
        }
        if (f[i][j] != null) {//如果这个位置值不是空的,就直接返回这个数
            return f[i][j];//证明曾经这里有值放过了,避免重复计算
        }
        int ans = 0;//用来记录数
        for (int k = j; k < 5; ++k) {//这是用来递归每个字母能组排几次的
            ans += dfs(i + 1, k);
        //n越大,i存放的值就越大 因为每次[i][k]值最大的肯定是最开始回溯的
        }
        return f[i][j] = ans;
    }
}

两种 

第一种纯纯的数学运算

限制条件的情况下,按字母表顺序排列,所以每个字母都不能用前一个字母。

这种情况下每个字母可以使用的数量与n挂钩,而每个字母可以调用后面的字母进行组排最大的顺序是4 3 2 1 次 也就是说 每次都在递减

所以可以得出C(n+5-1,5-1)=C(n+4,4)

其中5是要用所有字母的个数,-1是为了递减因为限制条件,n就是每个字母可以使用的次数

前面的n+5-1代表每个字母所能排列组合的最大次数递减,后面的5-1就是每次更替字母所需组排的最小递减(可以自己举个例子试试)

* 15 10 6 3 1 n=3 (5+4+3+2+1 4+3+2+1 3+2+1 2+1 1)
* 5 4 3 2 1 n=2 (1+1+1+1+1 1+1+1+1 1+1+1 1+1 1)
* 1 1 1 1 1 n=1 不需要更替

第二种纯纯的回溯递归

大神的解释

 很难绷,本来直接数学干掉,虽然没写出来但是能看出来是一道数学规律题,而且当时也想到递归回溯了,因为递归学的比较抽象,最终还是选择数学法,但是好歹还是能理解的,无非就是找规律,找每个字母重复的次数,再找每次组排最小字母组排的次数,基本就是C(n+4)/C(4)了

再大白话就是上面那个算式

(n+4)*(n+3)*(n+2)*(n+1)/(4 * 3 * 2 *1)

回溯递归要理解就得思考dfs是从0开始还是从n-1倒着开始,很头疼,到现在还是不太理解,大神是从【0,0】的位置开始的,但是从结果上看最终返回的是1 也就是数是从大到小倒叙倒着来的,

从数学法里面那3个规律来看,每次递归的都会被累加,最开始递归的数是最大的,之后会慢慢变小,而且因为是2维数组,会将每个值都放进去,也就是说,以那个例子为例,他的dfs是从15开始向下找,然后再往右来从10开始往下再找,很难理解吧。

八股

mysql默认搜索引擎

默认以innodb为搜索引擎,它支持主外键,事务 ,且是行锁,缓存索引和真实数据,适合高并发,但是内存要求高

而myisam不支持主外键和事务,是表锁,缓存索引不缓存真实数据,比 innodb性能好

InnoDB默认可以创建16个索引

  • InnoDB支持事务,MyIsam不支持事务,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放到begin 和 commit之间,组成一个事务;
  • InnoDB支持外键,而MyIsam不支持,对一个包含外键的InnoDB表转成MyIsam表会失败
  • InnoDB是聚集索引,数据文件和索引绑定在一块,必须要有主键,通过主键索引效率很高,但是辅助索引需要两次查询,先查询到主键,然后在通过主键查询到数据。因此主键不应该过大。主键过大的时候,其它索引也会很大。而MyIsam是非聚集索引,数据和文件是分离的,索引保存的是数据文件的指针,主键索引和辅助索引是独立的。
  • InnoDB不支持全文检索,而MyIsam支持全文检索,查询效率上MyIsam要高

mysql跟redis存储区别

mysql存储在硬盘上,redis存储在内存上,索引redis比mysql存储快

mysq的索引和检索原理

索引是为了帮助mysql高效获取数据的数据结构,索引mysql索引的本质就是数据结构

可以简单的理解为:排好序的快速查找B+树数据结构,B+树中的B代表平衡(balance) 而不是 二叉(binary)

索引是一种特定算法的数据结构,所以可以理解成一个二叉树,每个节点包括索引值对应的数据指针,这样就可以快速检索符合条件的记录

聚簇索引和非聚簇索引

  • 聚簇索引:将数据存储与索引放到一块,索引结构的叶子节点保存了行数据
  • 非聚簇索引:将数据与索引分开,索引结构的叶子节点指向了数据对应的位置

innodb中,在聚簇索引之上的创建的索引都是辅助索引也就是说 非聚簇索引都是辅助索引,辅助索引访问数据总是需要二次查找,查找指向聚簇索引保存的数据,这就是回表操作

聚簇索引具有唯一性(主键),一个表仅有一个聚簇索引,表中行的物理顺序与索引中行的物理顺序是一致的,创建任何非聚簇索引前必须要先创建聚簇索引

聚簇索引默认主键,如果未定义,会以一个唯一且非空的索引代替。

而myisam使用的非聚簇索引,所以和两颗b+树看上去没什么不同,节点结构一致,存储的内容不同,都指向真正的表数据,由于索引树是独立的,所以通过辅助减少查询无需访问主键的索引树

mybatis_plus学习第二天

算法学的我现在头晕乎乎的

条件构造器和常用接口

eq 就是 equal等于
ne就是 not equal不等于
gt 就是 greater than大于
lt 就是 less than小于
ge 就是 greater than or equal 大于等于
le 就是 less than or equal 小于等于
in 就是 in 包含(数组)
isNull 就是 等于null
between 就是 在2个条件之间(包括边界值)
like 就是 模糊查询

or() 或

wapper

Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql where 条件
QueryWrapper : 查询条件封装
UpdateWrapper Update 条件封装
AbstractLambdaWrapper : 使用 Lambda 语法
LambdaQueryWrapper :用于 Lambda 语法使用的查询 Wrapper
LambdaUpdateWrapper Lambda 更新封装 Wrapp

QueryWrapper查询条件封装

selectList 查询

like between innotnull

 @Autowired
    private UserMapper userMapper;

    @Test
    public void test01(){
        //查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息
        //SELECT uid AS id,user_name AS name,age,email,is_deleted 
        //FROM t_user WHERE is_deleted=0
        //AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name", "a")
                .between("age", 20, 30)
                .isNotNull("email");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

selectList排序

orderby


@Test
    public void test02(){
        //查询用户信息,按照年龄的降序排序,若年龄相同,则按照id升序排序
        //SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("uid");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

delete 删除

is null 添加了逻辑删除,所以是 update语句

 @Test
    public void test03(){
        //删除邮箱地址为null的用户信息
        //UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("result:"+result);
    }

update修改

gt like or isnull

 @Test
    public void test04(){
        //将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
        //UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age", 20)
                .like("user_name", "a")
                .or()
                .isNull("email");
        User user = new User();
        user.setName("小明");
        user.setEmail("test@atguigu.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("result:"+result);
    }

条件的优先级

update  and 

 @Test
    public void test05(){
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        //lambda中的条件优先执行
        //UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name", "a")
                .and(i->i.gt("age",20).or().isNull("email"));
        User user = new User();
        user.setName("小红");
        user.setEmail("test@atguigu.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("result:"+result);
    }

组装select字句

selectmaps

  @Test
    public void test06(){
        //查询用户的用户名、年龄、邮箱信息
        //SELECT user_name,age,email FROM t_user WHERE is_deleted=0
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_name", "age", "email");
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }

组装子查询

selectList insql

 @Test
    public void test07(){
        //查询id小于等于100的用户信息
        //SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid <= 100))
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid", "select uid from t_user where uid <= 100");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

UpdateWrapper Update 条件封装

update


    @Test
    public void test08(){
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.like("user_name", "a")
                .and(i -> i.gt("age", 20).or().isNull("email"));
        updateWrapper.set("user_name", "小黑").set("email","abc@atguigu.com");
        int result = userMapper.update(null, updateWrapper);
        System.out.println("result:"+result);
    }

condition

思路一 模拟开发中组装条件的情况-不用condition

使用if

 @Test
    public void test09(){
        //SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)
        String username = "a";
        Integer ageBegin = null;
        Integer ageEnd = 30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if(StringUtils.isNotBlank(username)){
            //isNotBlank判断某个字符创是否不为空字符串、不为null、不为空白符
            queryWrapper.like("user_name", username);
        }
        if(ageBegin != null){
            queryWrapper.ge("age", ageBegin);
        }
        if(ageEnd != null){
            queryWrapper.le("age", ageEnd);
        }
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

思路二---使用condition组件条件

不用if判断了 因为里面有条件判断属性

  @Test
    public void test10(){
        String username = "a";
        Integer ageBegin = null;
        Integer ageEnd = 30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username), "user_name", username)
                .ge(ageBegin != null, "age", ageBegin)
                .le(ageEnd != null, "age", ageEnd);
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

LambdaQueryWrapper 用于Lambda语法使用的查询Wrapper

 第二个表达式是判断字段是否写错

直接访问实体类的对象属性 User::getName

同理下面都是一样的


    @Test
    public void test11(){
        //SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)
        String username = "a";
        Integer ageBegin = null;
        Integer ageEnd = 30;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
                .ge(ageBegin != null, User::getAge, ageBegin)
                .le(ageEnd != null, User::getAge, ageEnd);
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

LambdaUpdateWrapper Lambda 更新封装Wrapp

同样 lambdaUpdateWrapper 会

  @Test
    public void test12(){
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.like(User::getName, "a")
                .and(i -> i.gt(User::getAge, 20).or().isNull(User::getEmail));
        updateWrapper.set(User::getName, "小黑").set(User::getEmail,"abc@atguigu.com");
        int result = userMapper.update(null, updateWrapper);
        System.out.println("result:"+result);
    }

总结

最近写算法题总是很倔,每天也就学个5或6小时,总会在算法题里面扔进去俩个小时以上,今天更是不甘心看不明白回溯,干进去三个小时,最终还是似懂非懂,后面八股又不是现成题,都是总结人家写好的笔记,不是光背,反正就是很浪费时间,以至于今天mybatis_plus竟然没学完(剩一小时),不是不能学了,而是头很痛了,看的眼酸,又得做笔记又得敲代码跟找bug的,一小时半小时看课,二十分钟找bug或者敲代码,十分钟写笔记,我在想算法题还有必要追根到底吗,很难绷啊,每次写完算法题都想睡觉回回神。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值