每日1+1题(有效的字母异位词+两个数组的交集)+java学习反思
进入哈希表的学习章节,做了两题还没有发现哈希表的特殊之处,或许时间稍微快了点?
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1: 输入: s = “anagram”, t = “nagaram” 输出: true
示例 2: 输入: s = “rat”, t = “car” 输出: false
说明: 你可以假设字符串只包含小写字母。
题意:给定两个数组,编写一个函数来计算它们的交集。
说明: 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。
//有效的字母异位词
// 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;
}
}