LOADING

加载过慢请开启缓存 浏览器默认开启

2023/10/21

每日1+1题(有效的字母异位词+两个数组的交集)+java学习反思

进入哈希表的学习章节,做了两题还没有发现哈希表的特殊之处,或许时间稍微快了点?

力扣题目链接(opens new window)

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1: 输入: s = “anagram”, t = “nagaram” 输出: true

示例 2: 输入: s = “rat”, t = “car” 输出: false

说明: 你可以假设字符串只包含小写字母。

力扣题目链接(opens new window)

题意:给定两个数组,编写一个函数来计算它们的交集。

349. 两个数组的交集

说明: 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。

//有效的字母异位词
// Created by 徐昊岩 on 2023/10/21.
//两个数组的交集
#include "string"
#include "vector"
#include "unordered_set"
using namespace std;
class Solution {
public:
    bool isAnagram(string s, string t) {
        int count[26]={0};
        int i=0;
        for(i=0;i<s.size();i++) count[s[i]-'a']++;   //有时候只需要一个相对值,并不需要去记住'a'的asc2编码
        for(i=0;i<t.size();i++) count[t[i]-97]--;
        for(i=0;i<26;i++) if(count[i]!=0) return false;
        return true;
    }
};
class Solution2 {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> uset1(nums1.begin(),nums1.end());
        unordered_set<int> uset2(nums2.begin(),nums2.end());
        vector<int> result;
        for(auto it=uset1.begin();it!=uset1.end();it++){
            if(uset2.find(*it)!=uset2.end()){
                result.push_back(*it);
            }
        }
        return result;
    }
};
//失败优化,但好歹学到了一些stl的使用
class Solution3 {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> uset(nums1.begin(),nums1.end());
        vector<int> result;
        for(auto it=uset.begin();it!=uset.end();it++){
            for(int num:nums2){  //for each循环,对任何可迭代对象(实现了迭代器)都能从头遍历
                if(uset.find(num)!=uset.end()) result.push_back(num);
            }
        }
        return result;   //也可以创造vector<int>(a.begin(),a.end())匿名变量
    }
};

java学习反思

这两天或者说这几个月,总感觉java学习太过囫囵吞枣,学了会尚硅谷的java0基础,感觉太过0基础,跳了很多前面的类C语法,也2倍速看了好多面向对象视频,而且光是看,懒得去写。结果尚硅谷面向对象还没咋看完,又感觉自己需要实践实践感受编程的乐趣,于是又去看黑马程序员的Springboot项目(也跳了前面的前端部分),结果看了不到1/3又感觉自己java语法不行了,来回倒腾之后又摆烂了好久,感觉自己已经过了“编程语言的学习红利期”,即掌握了一定语法后,对其它语言语法感觉很类似,于是失去了学习的热情。 之后跟着廖雪峰的文档学完了git,边敲边看文档这种方式感觉还挺让我沉浸的,遂转战廖雪峰的java教程

然而,又由于之前学了尚硅谷的java语法,看文档又失去了耐心,属于是捡了芝麻又丢了芝麻。

最近才回想起《动手学深度学习v2》的作者沐神的教诲,学习编程的关键就在于“动手学”,如果你不亲自上手敲一遍代码,那不叫学编程。“动手学”不仅可以增加你对代码的理解、熟练度,还能让你更加专注

于是决定重学部分廖雪峰java教程,就从java核心类开始,希望我能秉持 “动手学” 的精神,将其贯彻到每一种语言的学习中!

package java_learning;

import java.io.UnsupportedEncodingException;

public class core_learning {
    /*
    public static void main(String[] args) {
        String s1="Hello";
        String s2=new String("Hello"); //new 类() 中的()一般是用于初始化对象
        String s3=new String(new char[]{'H','e','l','l','o'});
        String s4="Hello";
        System.out.println(s1.toUpperCase()+'\n'+s2+'\n'+s3+'\n'+s1);
        //s1.toUpperCase()返回s1字符串的大写形式,但并不修改s1本身
        //或许方法要么是自修改,要么是返回修改
        System.out.println(s1==s3);
        System.out.println(s1==s4);
        //或许像C语言一样只有字符串可以视为常量地址,注意new是新创建
        System.out.println(s1.equals(s3));  //equals比较的才是字符串值的大小
        "Hello".startsWith("He"); // true
        "Hello".endsWith("lo"); // true
        System.out.println("Hello".substring(2));// "llo"
        //substring接收两个参数,必须给出开头index,默认给出结尾index
        System.out.println('\u3000'+" \tHello\r\n ".trim());
        //注意:trim()并没有改变字符串的内容,而是返回了一个新字符串。
        //'\u3000'类似中文的空格字符,可以被strip消除
        "".isEmpty(); // true,因为字符串长度为0
        "  ".isEmpty(); // false,因为字符串长度不为0
        "  \n".isBlank(); // true,因为只包含空白字符
        " Hello ".isBlank(); // false,因为包含非空白字符
        System.out.println(s1.replace("ello","i"));
        //replace方法既可以替换字符,也可以替换字符串
        //返回修改式正则表达式替换,稍后再研究
        System.out.println(s1.replaceAll("[\\s]+", ",")); // "A,B,C,D"
        //String的join方法,除第一个参数外,还可以给出一个字符数组
        System.out.println(String.join("&",s1,s2,s3));
        //后缀.formatted() 类python
        System.out.println("我名为:%s,%d岁".formatted("徐昊岩",20));

        //好在基本类型仍然遵从c语言格式的类型转换
        int n1=(int)2.5;
        //字符串类型与基本类型互相转化,包装类的parse+xxx方法
        int i1=Integer.parseInt("0123");
        int n2 = Integer.parseInt("ff", 16); // 按十六进制转换,255
        System.out.println(i1);
        boolean b1=Boolean.parseBoolean("true");
        //System.out.println(boolean instanceof Boolean);  编译错误,说是Boolean是一个包装类,至于包装类和基本数据类型有什么区别,以后再来判断


        //要特别注意,Integer有个getInteger(String)方法,
        //它不是将字符串转换为int,而是把该字符串对应的"系统变量"转换为Integer:

        Integer.getInteger("java.version");// 版本号,11

        //String类型具有不可变特性,你不能通过索引的方式直接修改String某个元素的值,但是字符数组char[]可以
        //注:写算法还是使用char[]吧
        char[] chs=new char[]{'1','2'};
        chs[0]='4';
        String s5=new String(chs); //复制式赋值
        //通过new String(char[])创建新的String实例时,它并不会直接引用传入的char[]数组,而是会复制一份,
        //所以,修改外部的char[]数组不会影响String实例内部的char[]数组,因为这是两个不同的数组。

        //赋值的两种方法:引用式赋值&复制式赋值,引用式会共享地址,随赋值者改变而改变

        //byte 是 Java 中的一个基本数据类型,用于表示 8 位的有符号整数。
        byte[] byte1="Hello".getBytes();  //默认方式转码
        System.out.println(byte1);
        //如果不使用默认转码方式,java强制你去检查一个编译时异常
        //否则会报错
        try {
            //编码
            byte[] byte2="Hello".getBytes("UTF-8");  //UTF-8方式转码
            System.out.println(byte2);
            //解码
            String from_byte=new String(byte2,"UTF-8");
            System.out.println(from_byte);
        }
        catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
    }
    */


    /*
    public static void main(String[] args){
        //Java编译器对String做了特殊处理,使得我们可以直接用+拼接字符串。
        //虽然可以直接拼接字符串,但是,在循环中,每次循环都会创建新的字符串对象,然后扔掉旧的字符串。这样,绝大部分字符串都是临时对象,不但浪费内存,还会影响GC效率。
        //为了能高效拼接字符串,Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder中新增字符时,不会创建新的临时对象:
        StringBuilder sb1=new StringBuilder("Hello,");

        //可以StringBuilder理解为一个动态字符串,相比char[],其内存可以动态增加
        for(int i=0;i<3;i++){
            sb1.append(i)
                    .append("徐")
                    .append("好")
                    .append("眼")
                    .insert(0+i,i);  //每执行一遍就加一个
        }
        //上述代码写法称为  “链式操作”,原因是.append()方法返回this指针,即当前对象
        //明白了原理,你也可以写一个链式操作
        //链式操作的好处:关键在于多种链式操作叠加使用更加方便,代码间接性、可读性更高
        //不需要一个操作写一行
        System.out.println(sb1);
        //注意:对于普通的字符串+操作,并不需要我们将其改写为StringBuilder,因为Java编译器在编译时就自动把多个连续的+操作编码为StringConcatFactory的操作。在运行期,StringConcatFactory会自动把字符串连接操作优化为数组复制或者StringBuilder操作。

        String[] fields = { "name", "position", "salary" };
        String table = "employee";
        String insert = buildInsertSql(table, fields);
        System.out.println(insert);
        String s = "INSERT INTO employee (name, position, salary) VALUES (?, ?, ?)";
        System.out.println(s.equals(insert) ? "测试成功" : "测试失败");

    }
    static String buildInsertSql(String table,String[]fields){
        StringBuilder sb=new StringBuilder(table);
        //把字符串变为动态字符串,便于修改
        sb.insert(0,"INSERT INTO ");
        //还有sb.delete()方法,说明确实可以理解为动态字符串替代char[]使用!
        sb.append(" (%s, %s, %s) VALUES (?, ?, ?)".formatted(fields[0],fields[1],fields[2]));
        return new String(sb); //再把动态数组转化回来,也可以用.toString()方法
    }
    */

    /*
    public static void main(String[] args){
        //研究for each循环
        String[] names = {"Bob", "Alice", "Grace"};
        var sb = new StringBuilder();
        sb.append("Hello ");
        for (String name : names) {  //for each循环,可以用于实现了iterable接口的类(数组、String等)
            sb.append(name).append(", ");
        }
        // 注意去掉最后的", ":
        sb.delete(sb.length() - 2, sb.length());
        sb.append("!");
        System.out.println(sb.toString());
    }

     */


    /*
    在 Java 中,增强型的 for 循环(也称为 for-each 循环)可以用于遍历以下类型:
    1数组:可以遍历任何类型的数组,包括基本数据类型和引用数据类型。例如:
    java
    int[] numbers = {1, 2, 3, 4, 5};
    for (int num : numbers) {
        System.out.println(num);
    }
    2实现了 Iterable 接口的集合类:可以遍历实现了 Iterable 接口的集合类,如 List、Set、Queue 等。例如:

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    for (String name : names) {
        System.out.println(name);
    }
    3实现了 Iterable 接口的自定义类:如果你的自定义类实现了 Iterable 接口,就可以使用增强型 for 循环进行遍历。需要实现 Iterator 方法。例如:

    public class MyIterableClass implements Iterable<String> {
        private String[] data = {"A", "B", "C"};

        @Override
        public Iterator<String> iterator() {
            return Arrays.asList(data).iterator();
        }
    }

    MyIterableClass iterableObj = new MyIterableClass();
    for (String item : iterableObj) {
        System.out.println(item);
    }
    需要注意的是,for each循环只能进行正向遍历,并且无法改变遍历的集合或数组中的元素。如果需要在遍历过程中进行删除、修改等操作,可以考虑使用普通的for循环或迭代器。
    java中的迭代器: Iterator<String> iterator
     */


    //包装类型,是!“包含基本类型”的引用类型,并不是基本类型的父类或是子类,基本类型不能称为"类class"
    public static void main(String[] args){
        //引用类型可以为null空,但基本类型不能为空null
        String s=null;
        //int n=null; //compile error!
        Integer n=new Integer(80); //会有红色编译警告,但仍然可以运行
        Integer n2=Integer.valueOf(80);
        Integer n3=Integer.valueOf("80");
        System.out.println(n2+n3);
        System.out.println(n2.intValue()+n3.intValue());

        //.valueOf()和intValue()方法可以实现互相转化,为了方便,java编译器可以帮我们自动在int和Integer之间转型
        Integer auto1=10; // 编译器自动使用Integer.valueOf(int)
        int auto2=auto1; // 编译器自动使用Integer.intValue()

        //这种直接把int变为Integer的赋值写法,称为自动装箱(Auto Boxing),
        //反过来,把Integer变为int的赋值写法,称为自动拆箱(Auto Unboxing)。
        //注意:自动装箱和自动拆箱只发生在编译阶段,目的是为了少写代码。

        final int a=10;  //final可以视作c/cpp的const,表明变量不可变/方法不可重写/类不可继承
        //Integer应当用.equals()方法去比较,而不是==!
        //仔细观察结果的童鞋可以发现,==比较,较小的两个相同的Integer返回true,较大的两个相同的Integer返回false,这是因为Integer是不变类,编译器把Integer x = 127;自动变为Integer x = Integer.valueOf(127);,为了节省内存,Integer.valueOf()对于较小的数,始终返回相同的实例,因此,==比较“恰好”为true,但我们绝不能因为Java标准库的Integer内部有缓存优化就用==比较,必须用equals()方法比较两个Integer。

        //因为Integer.valueOf()可能始终返回同一个Integer实例,因此,在我们自己创建Integer的时候,以下两种方法:
        //方法1:Integer n = new Integer(100);
        //方法2:Integer n = Integer.valueOf(100);
        //方法2更好,因为方法1总是创建新的Integer实例,方法2把内部优化留给Integer的实现者去做,即使在当前版本没有优化,也有可能在下一个版本进行优化。
        //我们把能创建“新”对象的静态方法称为静态工厂方法。Integer.valueOf()就是静态工厂方法,它尽可能地返回缓存的实例以节省内存。

        Boolean b1=Boolean.TRUE;
        boolean b2=b1;
        Integer i1=Integer.MAX_VALUE;
        int i2=i1;
        //返回某类型占用的bit/byte数量
        int sizeofLong=Long.SIZE;
        int bytesofLong=Long.BYTES;

        // 向上转型为Number:
        Number num = Integer.valueOf(999);
        // 获取byte, int, long, float, double:
        byte b4 = num.byteValue();
        int n4 = num.intValue();
        long ln4 = num.longValue();
        float f4 = num.floatValue();
        double d4 = num.doubleValue();
        //在Java中,并没有无符号整型(Unsigned)的基本数据类型。byte、short、int和long都是带符号整型,
        //最高位是符号位。而C语言则提供了CPU支持的全部数据类型,包括无符号整型。
        //无符号整型和有符号整型的转换在Java中就需要借助包装类型的静态方法完成。
        //Byte.toUnsignedInt(x)

    }
    //让一个类只包含一个int成员,就可以视其为int的包装类,包含互相转化的方法
    public class _Integer {
        private int value;

        public _Integer(int value) {
            this.value = value;
        }

        public int intValue() {
            return this.value;
        }
    }

    //javaBean(一种格式化的类),具有私有属性,公有的设置与获得方法
    //在IDEA中,右击属性选择generator可以快速生成javaBean规范方法
    //还可以快速生成构造器、重载Object关键方法.....,十分便捷
    public class Person{
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        private String name;
        private int age;
    }

}