public class Test3{
public static void main(String[] args) {
System.out.println(100 % 3); // 1
System.out.println(100 % 3.0); // 1.0
System.out.println(100 % 3.3); // 1.0000000000000053
}
)
C语言取模操作符只能针对整型类型。Java取模操作符可以是浮点数
方法通常存储在进程中的哪一区()
A堆区
B栈区
C全局区
D方法区
public class TestDemo {
public static void main(String[] args) {
String s1 = "abcd";
String s2 = s1.toLowerCase(); // 与 "abcd" 一样 返回原来的对象
System.out.println(s1 == s2); // true
System.out.println(s1.toLowerCase() == "abcd"); // true
String s3 = "Admin" ;
String s4 = s3.toLowerCase(); // 大写转小写 不一样 产生了一个新的对象
System.out.println(s3 == "admin"); // false
}
}
在使用super和this关键字时,以下描述正确的是()
- A. 在子类构造方法中使用 super() 显示调用父类的构造方法,super() 必须写在子类构造方法的第一行,否则编译不通过
- B. super()和this ()不一定要放在构造方法内第一行
- C. this() 和 super() 可以同时出现在一个构造函数中
- D. this() 和 super() 可以在 static 环境中使用,包括 static 方法和 static 语句块
super()
和 this()
都要放在子类构造方法的第一行,所以无法同时出现在一个构造函数中
// 如下代码的输出结果是什么?
public class Test {
public int aNethod() {
static int i = 8;
i++;
return i;
}
public static void main(String args[]) {
Test test = new Test();
test.aNethod();
int j = test.aNethod();
System.out.println(j);
}
}
被 static
修饰的变量是类变量,属于类,不属于方法,编译失败
下列哪一种叙述是正确的()
- A. abstract修饰特可修饰字段、方法和类
- B. 抽象方法的body部分必须用一对大括号 {} 包住
- C. 声明抽象方法,大括号可有可无
- D. 声明抽象方法不可写出大括号
abstract
不能修饰字段
抽象方法没有方法体(没有 { }, 不能执行具体代码)
abstract class A {
abstract void fun() {}; // Abstract methods cannot have a body
}
下列说法正确的有:()
- A. class 中的 constructor 不可省略
- B. constructor 必须与 class 同名,但方法不能与 class 同名
- C. constructor 在一个对象被 new 时执行
- D. 一个 class 只能定义一个 constructor
方法可以和类名同名,例如构造方法
// 选项中哪一行代码可以替换 // add code here 而不产生编译错误 public abstract class MyClass { public int constInt = 5; // add code here public void method() { } }
- A. public abstract void method (int a);
- B. consInt = constInt + 5;
- C. public int method();
- D. public abstract void anotherMethod() {}
B:成员变量的赋值必须放在方法里
D:去花括号,加分号,变抽象方法
// 以下程序的输出结果为 class Base{ public Base(String s){ System.out.print("B"); } } public class Derived extends Base{ public Derived (String s) { System.out.print("D"); } public static void main(String[] args){ new Derived("C"); } }
- A. BD
- B. DB
- C. C
- D. 编译错误
修改:1、写一个 Base 的不带参数的构造方法。2、Base 的构造方法去参数,改成无参构造方法。3、或者在 Derived 的构造方法中加入 super(“A”),先为父类构造。
下列哪种说法是正确的?
A. 实例方法可直接调用超类的实例方法
B. 实例方法可直接调用超类的类方法
C. 实例方法可直接调用本类的类方法
D. 实例方法可直接调用其他类的实例方法
// 有以下代码片段: String str1="hello"; String str2="he"+ new String("llo"); System.out.println(str1==str2);
请问输出的结果是:
- A. true
- B. 都不对
- C. null
- D. false
比较的是对象地址,String str1=“hello”; 这样创建字符串是存在于常量池中,
String str2=new String(“hello”); str2存在于堆中,所以str1和str2指向的并 不是同一个对象
// 程序读入用户输入的一个值,要求创建一个自定义的异常,如果输入值大于 10 ,
// 使用 throw 语句显式地引发异常,异常输出信息为 ”something’swrong!”,语句为()
*A if(i>10)throw new Exception("something’swrong!");
B if(i>10)throw Exception e("something’swrong!");
C if(i>10) throw new Exception e("something’swrong!");
D if(i>10)throw Exception( "something’swrong!");
以下关于集合类 ArrayList 、 LinkedList 、 HashMap 描述错误的是:
A. HashMap实现Map接口,它允许任何类型的键和值对象,并允许将null用作键或值
B. ArrayList和LinkedList均实现了List接口
C. 添加和删除元素时,ArrayList的表现更佳
D. ArrayList的访问速度比LinkedList快
ArrayList 底层是数组,LinkedList 是链表,HashMap 是数组加链表
Java程序中的类名称必须与存放该类的文件名相同。
- A. 对
- B. 错
不是 public 的类
下面哪些类实现或继承了 Collection 接口?
A HashMap
B ArrayList
C Vector
D Iterator
HashMap 不是,Iterator 是迭代器
下面关于abstract关键字描述错误的是()
- A abstract关键字可以修饰类或方法
- B final类的方法都不能是abstract,因为final类不能有子类
- C abstract类不能实例化
- D abstract类的子类必须实现其超类的所有abstract方法
如果是被 abstract 类继承,可以不重写,但普通类继承,需要重写父类所有的 abstract 方法
对于abstract声明的类,下面说法正确的是
A 可以实例化
B 不可以被继承
C 子类为abstract
D 只能被继承
E 可以被抽象类继承
abstract 类不能实例化,可以被继承,子类可以是普通类,
不是只能被继承,可以用作组合:将一个类的实例作为另外一个类的字段
abstract class U {
}
public class TestDemo {
public U u;
public static void main(String[] args) {
}
}
// 以下代码结果是什么? public class foo { public static void main(String sgf[]) { StringBuffer a = new StringBuffer("A"); StringBuffer b = new StringBuffer("B"); operate(a, b); System.out.println(a + "." + b); } static void operate(StringBuffer x, StringBuffer y) { x.append(y); y = x; }
- A 代码可以编译运行,输出“AB.AB”。
- B 代码可以编译运行,输出“A.A”。
- C 代码可以编译运行,输出“AB.B”。
- D 代码可以编译运行,输出“A.B”。
y=x; 并没有改变 b 指向对象的值,指向将 y 指向了 x 所指向的对象(之前y和b指向同一个对象),打印的还是 b。
在JAVA中,假设A有构造方法A(int a),则在类A的其他构造方法中调用该构造方法和语句格式应该为()
A this.A(x)
B this(x)
C super(x)
D A(x)
下面代码的运行结果是()
public static void main(String[] args) {
String s;
System.out.println(“s=”+s);
}
A 代码编程成功,并输出”s=”
B 代码编译成功,并输出”s=null”
C 由于String s没有初始化,代码不能编译通过。
D 代码编译成功,但捕获到NullPointException异常
使用局部变量,需要初始化
关于抽象类与最终类,下列说法错误的是?
- A 抽象类能被继承,最终类只能被实例化。
- B 抽象类和最终类都可以被声明使用
- C 抽象类中可以没有抽象方法,最终类中可以没有最终方法
- D 抽象类和最终类被继承时,方法可以被子类覆盖
最终类:密封类,被 final 修饰的类,可以被实例化,不能被继承
final class F {
}
abstract class K {
}
public class Test {
F f;
K k;
public static void main(String[] args) {
F f1 = new F();
F f;
K k;
}
}
有六个元素 6,5,4,3,2,1,顺序入栈,问下列哪一个不是合法的出栈序列?()
- A. 5 4 3 6 2 1
- B. 4 5 3 1 2 6
- C. 3 4 6 5 2 1
- D. 2 3 4 1 5 6
// 阅读下列程序,选择哪一个是正确的输出结果 class HelloA { public HelloA() { System.out.println("I’m A class "); // 3 } static { System.out.println("static A"); // 1 } } public class HelloB extends HelloA { public HelloB() { System.out.println("I’m B class"); // 4 } static{ System.out.println("static B"); // 2 } public static void main (String[] args){ new HelloB(); } }
- A. static A I’m A class static B I’m B class
- B. I’m A class I’m B class static A static B
- C. static A static B I’m A class I’m B class
- D. I’m A class static A I’m B class static B
Math.round(11.5) 等于:()
A 11
B 11.5
C 12
D 12.5
round() :四舍五入
以下 _____ 不是 Object 类的方法
- A clone()
- B finalize()
- C toString()
- D hasNext()
hasNext() 是 Iterator 的方法
java 语言使用的字符码集是
- A. ASCII (大小字母,0-9,特殊字符)
- B. BCD (数字)
- C. DCB
- D. Unicode (Java 使用的)
以下说法错误的是()
- A 数组是一个对象
- B 数组不是一种原生类
- C 数组的大小可以任意改变
- D 在Java中,数组存储在堆中连续内存空间里
Java中,数据类型分为基本数据类型(或叫做原生类、内置类型)和引用数据类型。原生类是指基本数据类型。
数组不是原生类,是通过基本类型定义的 int[] a=new int[100];
// 以下代码输出结果是什么?
public class Test {
public static void main(String[] args) {
System.out.println(new B().getValue());
// new B()后打印的的是 22
// 然后调用getValue 返回得到的是17 最后打印17
}
static class A {
protected int value; // 10
public A(int v) { // 5
setValue(v);
// 调用的是子类重写的方法 也就是 B 的 setValue
}
public void setValue(int value) {
this.value = value; // 10 22 16 34
}
public int getValue() {
try {
value++; // 11 17
return value; // 11 17
} catch (Exception e) {
System.out.println(e.toString());
} finally {
this.setValue(value); // 还是调用 B 的:传入 22 17
System. out.println(value); // 打印:22 34
}
return value;
}
}
static class B extends A {
protected B() {
super(5); // 5
setValue(getValue() - 3); // 11-3=8
}
public void setValue(int value) { // 5 11 8 17
super.setValue(2 * value); // 10 22 16 34
}
}
}
A 11 17 34
B 22 74 74
C 6 7 7
*D 22 34 17
// 以下代码 public class Test { static int cnt = 6; static{ cnt += 9; } } public static void main(String[] args) { System.out.println("cnt = " + cnt); } static{ cnt /= 3; };
cnt 的值是
- A cnt = 5
- B cnt = 2
- C cnt = 3
- D cnt = 6
静态代码块先执行, (6 + 9) / 3 = 5
java 中关于内存回收的正确说法是()
- A 程序员必须创建一个线程来释放内存
- B 内存回收程序负责释放无用内存
- C 内存回收程序允许程序员直接释放内存
- D 内存回收程序可以在指定的时间释放内存对象
JUnit主要用来完成什么?
- A 发送HTTP请求
- B 建立TCP连接
- C 集成测试
- D 单元测试
关于 JAVA 堆,下面说法错误的是()
- A 所有类的实例和数组都是在堆上分配内存的
- B 对象所占的堆内存是由自动内存管理系统回收
- C 堆内存由存活和死亡的对象,空闲碎片区组成
- D 数组是分配在栈中的
JAVA语言的下面几种数组复制方法中,哪个效率最高?
- A for循环逐一复制
- B System.arraycopy
- C Arrays.copyOf
- D 使用clone方法
1,for的速度之所以最慢是因为下标表示法每次都从起点开始寻位到指定下标处,
另外就是它每一次循环都要判断一次是否达到数组最大长度和进行一次额外的记录下标值的加法运算。
System.arraycopy 它是浅拷贝,也就是说对于非基本类型而言,它拷贝的是对象的引用,而不是去新建一个新的对象。
Arrays copyOf:
public static byte[] copyOf(byte[] original, int newLength) {
byte[] copy = new byte[newLength];
System.arraycopy(original, 0, copy,0, Math.min(original.length, newLength));
return copy;
}
System.arraycopy > Object.clone > Arrays.copyOf > for
()仅包含方法定义和常量值。
- A 接口
- B 变量
- C 单元
- D 成员
// 对文件名为Test.java的java代码描述正确的是() class Person { String name = "No name"; public Person(String nm) { name = nm; } } class Employee extends Person { String empID = "0000"; public Employee(String id) { empID = id; } } public class Test { public static void main(String args[]) { Employee e = new Employee("123"); System.out.println(e.empID); } }
- A 输出:0000
- B 输出:123
- C 编译报错
- D 输出:No name
没有 super ,加上 super(“xxx”);
// 有关下述Java代码描述正确的选项是____。 public class TestClass { private static void testMethod(){ System.out.println("testMethod"); } public static void main(String[] args) { ((TestClass)null).testMethod(); } }
- A 编译不通过
- B 编译通过,运行异常,报NullPointerException
- C 编译通过,运行异常,报IllegalArgumentException
- D 编译通过,运行异常,报NoSuchMethodException
- E 编译通过,运行异常,报Exception
- F 运行正常,输出testMethod
无论 new 多少个该类的实例,static 方法只有一份,属于类本身
在jdk1.5之后,下列 java 程序输出结果
int i = 0; Integer j = new Integer(0); System.out.println(i == j); // j 自动拆箱 System.out.println(j.equals(i));
- A true,false
- B true,true
- C false,true
- D false,false
- E 对于不同的环境结果不同
- F 程序无法执行
1、基本型和基本型封装型进行“==”运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer(0)会自动拆箱为int类型再进行比较,显然返回true;
2、两个Integer类型进行“==”比较,如果其值在-128至127,那么返回true,否则返回false, 这跟Integer.valueOf()的缓冲对象有关,这里不进行赘述。
3、两个基本型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true
4、基本型封装类型调用equals(),但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,再进行3中的比较。
int a=257;
Integer b=257;
Integer c=257;
Integer b2=57;
Integer c2=57;
System.out.println(a==b);
// System.out.println(a.equals(b)); 编译出错,基本型不能调用equals()
System.out.println(b.equals(257.0));
System.out.println(b==c);
System.out.println(b2==c2);
因此上面的代码的结果因此为 true, false, false, true
// 下面代码运行结果是()
public class Test{
public int add(int a,int b){
try {
return a + b;
}
catch (Exception e) {
System.out.println("catch语句块");
}
finally{
System.out.println("finally语句块");
}
return 0;
}
public static void main(String argv[]){
Test test = new Test();
System.out.println("和是:" + test.add(9, 34));
}
}
A catch语句块 和是:43
B 编译异常
*C finally语句块 和是:43
D 和是:43 finally语句块
// 下列Java代码中的变量a、b、c分别在内存的____存储区存放。
class A {
private String a = “aa”;
public boolean methodB() {
String b = “bb”;
final String c = “cc”;
}
}
A 堆区、堆区、堆区
B 堆区、栈区、堆区
*C 堆区、栈区、栈区
D 堆区、堆区、栈区
E 静态区、栈区、堆区
F 静态区、栈区、栈区
以下声明合法的是
- A default String s
- B public final static native int w( )
- C abstract double d
- D abstract final double hyperbolicCosine( )
代码片段:
byte b1 = 1, b2 = 2, b3, b6;
final byte b4 = 4, b5 = 6;
b6 = b4 + b5;
b3 = (b1 + b2);
System.out.println(b3+b6);
关于上面代码片段叙述正确的是()
- A 输出结果:13
- B 语句:b6 = b4 + b5 编译出错
- C 语句:b3 = b1 + b2 编译出错
- D 运行期抛出异常
final 修饰变量值与类型不会被改变,所以此处加号运算符没有转为 int,b6 = b4 + b5;
正确,而在 b3 = (b1 + b2);
中,b1 与 b2 转为 int,相加还是 int,而 b3 是 byte,编译出错
// 以下java程序代码,执行后的结果是() public class Test { public static void main(String[] args) { Object o = new Object() { public boolean equals(Object obj) { return true; } }; System.out.println(o.equals("Fred")); } }
- A Fred
- B true
- C 编译错误
- D 运行时抛出异常
首先,创建了一个匿名内部类,并将所创建的匿名对象赋给 Object (多态:子类对象赋给超类引用)。同时,该匿名内部类重写了 Object 类的 equals 方法。Object 是所有类的父类,“Fred” 是字符串,String 是类类型,继承自 Object 。根据多态及覆盖原则,会调用匿名内部类重写后的 equals 方法,所以选 B。
// 执行以下程序后的输出结果是(AB,B)
public class Test {
public static void main(String[] args) {
StringBuffer a = new StringBuffer("A");
StringBuffer b = new StringBuffer("B");
operator(a, b);
System.out.println(a + "," + b);
}
public static void operator(StringBuffer x, StringBuffer y) {
x.append(y); y = x;
}
}
下面所示的java代码,运行时,会产生()类型的异常
int Arry_a[] = new int[10]; System.out.println(Arry_a[10]);
- A ArithmeticException
- B NullPointException
- C IOException
- D ArrayIndexOutOfBoundsException
以下java程序代码,执行后的结果是()
java.util.HashMap map = new java.util.HashMap(); map.put("name", null); map.put("name", "Jack"); System.out.println(map.size());
- A 0
- B null
- C 1
- D 2
size()
方法用于返回在此映射中的键 - 值映射关系的数量。 HashMap 在插入新元素时,会使用 equals() 方法判断集合中是否已经存在与新元素 key 相同的元素,如果存在,新元素会覆盖掉和他 key 相同的对象。 HashMap 允许 null 作为 key / value ,因此map.put(“name”,null); 会在 map 集合中存入 key 为 “name”,value 为 null 的对象。map.put(“name”,“Jack”); 会在 map 集合中存入key 为 “name”,value 为 “Jack” 的对象。前后两次存入的对象的 key 都为 “name” ,因此刚存入的 key 为 “name”,value 为 null 的对象会被覆盖掉,即 map 中只有一个 key 为 “name”,value 为 “Jack” 的对象。map.size() 为 1。
以下描述正确的是
- A CallableStatement 是 PreparedStatement 的父接口
- B PreparedStatement 是 CallableStatement 的父接口
- C CallableStatement 是 Statement 的父接口
- D PreparedStatement 是 Statement 的父接口
public interface CallableStatement extends PreparedStatement {
public interface PreparedStatement extends Statement {
下列关于容器集合类的说法正确的是?
- A LinkedList 继承自 List
- B AbstractSet 继承自 Set
- C HashSet 继承自 AbstractSet
- D WeakMap 继承自 HashMap
A、B 中 List
和 Set
是接口,应该是 实现 而不是 继承
C : AbstractSet 是抽象类,原码:public class HashSet extends AbstractSet
D : LinkedHashMap 继承自 HashMap
提供Java存取数据库能力的包是( )
- A java.sql
- B java.awt
- C java.lang
- D java.swing
注解:java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。此 API 包括一个框架,凭借此框架可以动态地安 装不同驱动程序来访问不同数据源。
以下哪个不是对 add 方法的重载?
public class Test { public void add(int x, int y, int z) {} }
- A. public int add(int x, int y, float z) {return 0};
- B. public int add(int x, int y, int z) {return 0};
- C. public void add(int x, int y) {};
- D. 以上都不是
规则:参数列表不同
下面整型常量 i 的定义中,正确的是:
- A. final i;
- B. static int i;
- C. static final int i = 234;
- D. final float i = 3.14f;
题目要求整型常量
// 以下java程序代码,执行后的结果是
public class TestDemo {
public void add(Byte b) {
b = b++;
}
public void test() {
Byte a = 127;
Byte b = 127;
add(++a);
System.out.println(a + " ");
add(b);
System.out.println(b + " ");
}
}
a 是 Byte,范围 -128 - 127,++a 后 a 为 -128。add 方法中 128 传入,后置++,形参 b 还是 128,但是输出的是 a ,和形参 b 无关。
b 传入 add,形参 b 后置 ++,为127,输出的是 b, 与形参 b 无关,打印:-128 127
一个关系数据库文件中的各条记录 () 。
- A 前后顺序不能任意颠倒,一定要按照输入的顺序排列
- B 前后顺序可以任意颠倒,不影响库中的数据关系
- C 前后顺序可以任意颠倒,但排列顺序不同,统计处理的结果就可能不同
- D 前后顺序不能任意颠倒,一定要按照关键字字段值的顺序排列
关系数据库的逻辑性强而物理性弱,因此关系数据库的各条记录前后顺序可以任意颠倒,不影响库中数据的关系
一名员工可以使用多台计算机,每台计算机只能由一名员工使用,则实体员工和计算机间的联系是( )
- A 一对多
- B 多对多
- C 多对一
- D 一对一
因为一名员工可以使用多台计算机,而一台计算机只能被一名员工使用,所以员工和计算机两个实体之间是一对多的关系。故本题答案为 A 选项。
下列关于视图的说法错误的是:
- A 视图是从一个或多个基本表导出的表,它是虚表
- B 视图一经定义就可以和基本表一样被查询、删除和更新
- C 某一用户可以定义若干个视图
- D 视图可以用来定义新的视图
视图是指计算机数据库中视图,是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来定义视图的查询所在的表,并且在引用视图时动态生成。
create view 视图名称 as select…
视图一经定义就无法修改,所以 B 中无法更新。D:create view test as select… from test
在 Mysql 中,订单表 ( 订单号,雇员代号,地区代号,订购日期 ) 中订单号为主键,要删除订单中前三年以前的信息, SQL 为:
- A delete from 订单表 where 订购日期
- B delete from 订单表 where 订购日期
- C delete from 订单表 where 订购日期
- D delete from 订单表 where 订购日期
语法:
DATEADD(datapart, number, date)
函数,在日期中添加或减去指定的时间间隔
datea 取值范围是
number 是希望添加的间隔数
date 是合法的日期表达式
getdate()
函数从 SQL Server 返回当前时间和日期MySQL 中没有 getdate(),DATEADD() 只有两个参数,此处是 SQL Server。
A、C 获取当前时间,+3 或 -3,不知道是什么时间单位。
D 中 yy 是年,-3 是往前三年,getdate 是当前日期
数据库管理系统是( )。
- A 操作系统的一部分
- B 在操作系统支持下的系统软件
- C 一种编译系统
- D 一种操作系统
数据库管理系统是数据库的机构,它是一种系统软件,负责数据库中数据组织、数据操纵、数据维护、控制及保护和数据服务等。是一种在操作系统之上的系统软件。
负责数据库中查询操作的数据库语言是( )。
- A 数据定义语言 DDL
- B 数据管理语言
- C 数据操纵语言 DML
- D 数据控制语言 DCL
数据定义语言 DDL
数据定义语言DDL用来创建数据库中的各种对象:表、视图、索引、同义词、聚簇等。例如:CREATE TABLE / VIEW / INDEX / SYN / CLUSTER
DDL 操作是隐性提交的,不能 ro11back。
数据操作语言 DML
主要负责数据的基本操作,包括查询及增加、删除、修改等操作。
数据控制语言 DCL
数据控制语言 DCL 用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等。如:
1)、GRANT:授权。
2)、ROLLBACK [WORK] To [SAVEPOINT]:回退到某一点。ROLLBACK:回滚。回滚命令使数据库状态回到上次最后提交的状态。其格式为:SQL > ROLLBACK。
3)、COMMIT [wORK] : 提交。
SQL 语句中修改表结构的命令是()
- A MODIFY TABLE
- B MODIFY STRUCTURE
- C ALTER TABLE
- D ALTER STRUCTURE
修改表结构的关键字都是
alter table 表名
,添加表字段:
- alter table table_name add 字段名称 字段类型
删除表字段:
- alter table table_name drop 字段名称
修改表字段:
- alter table table_name change 旧字段名称 新字段名称 字段类型
alter table table_name modify 字段名称 字段类型
在sql数据库中,哪个语句能校验整数列 i 的值不小于 1 不大于 10 ?
- A. i BETWEEN 1 AND 10
- B. i BETWEEN 0 AND 11
- C. i IN INTERVAL(0,11)
- D. i IN INTERVAL(1,10)
当
interval
作为一个函数时
它被当做一个比较函数,即 interva1(),如 interva1(4,0,1,2,3.45.6),第一个数 4 作为被比较数,后面的0,1,2,3,4,5,6 为比较数,然后将后面的数字依次与 4 进行比较,返回小于等于 4 的个数,所以,上述结果为 5,注意,只有将 4 后面的数字从小到大进行排列 ,interval 函数才能正常使用。若排序混乱,可以使用,但会影响最终结果
interval
作为关键字时
当 interval 作为一个关键字时,表示为时阿间隔,常用在 date_add()、 date_sub() 函数中,常用于时间的加减法,查询在当前时间之前 2 个小时的日期:select now() - interva1 2 hours;
SQL 查询语句中 WHERE 、 GROUP BY 、 HAVING 这些关键字区别和用法总结错误的是()
- A HAVING在查询语句中必须依赖于GROUP BY
- B WHERE子句用来限制SELECT语句从表中指定选取的行
- C GROUP BY子句用来分组WHERE子句的输出结果集
- D HAVING子句用来从分组的结果中筛选列
haing
是分组后条件过滤,筛选的是行
定义学生、教师和课程的关系模式 S (S#,Sn,Sd,Dc,SA )(其属性分别为学号、姓名、所在系、所在系的系主任、年龄); C ( C#,Cn,P# )(其属性分别为课程号、课程名、先修课); SC ( S#,C#,G) (其属性分别为学号、课程号和成绩),则该关系为( )
- A 第二范式
- B 第一范式
- C 第三范式
- D BCNF 范式
C:S表中的 所在系、所在系的系主任
是
范式:
范式是符合某一种级别的关系模式的集合。
关系数据库中的关系必须满足一定的要求,满足不同程度要求的为不同范式。目前关系数据库有六种范式:
第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、Boyce-Codd范式(BCNF)、第四范式(4NF)和第五范式(5NF)。
满足最低要求的范式是第一范式(1NF)。 在第一范式的基础上进一步满足更多要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了。
第一范式(1NF):列不可再分
- 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
- 第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到 “地址” 这个属性,本来直接将 “地址” 属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的"城市”部分,那么就非要将 “地址” 这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式
第二范式(ZNF):
属性完全依赖于主键
第二范式〈2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式〈2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。
每一行的数据只能与其中一列相关,即一行数据只做一件事。只要数据列中出现数据重复,就要把表拆分开来。第三范式(3NF):
属性不依赖于其它非主属性,属性直接依赖于主键
数据不能存在传递关系,即每个属性都跟主键有直接关系而不是间接关系。像: a–>b–>c 属性之间含有这样的关系,是不符合第三范式的。
比如Student表(学号,姓名,年龄,性别,所在院校,院校地址,院校电话)
这样一个表结构,就存在上述关系。学号–>所在院校–>(院校地址,院校电话)这样的表结构,我们应该拆开来,如下。
(学号,姓名,年龄,性别,所在院校)–(所在院校,院校地址,院校电话)BCNF范式:
- 所有属性都不传递依赖于关系的任何 候选键
题目中关系模式满足第二范式,但在学生表S中,学生所在系(Sd)依赖学号(S#),而所在系的系主任(Dc)又依赖学生所在系(Sd),存在依赖传递,不满足第三范式。
下面不属于数据库系统特点的是( )
- A 数据冗余度高
- B 数据具有完整性
- C 数据共享性好
- D 数据独立性高
数据库系统的特点:
数据共享性高,冗余度小;
具有高度的物理独立性,逻辑上一定的独立性和关联性
整体结构化,用数据模型描述;
由数据库系统提供数据安全性、完整性、并发控制和恢复能力。
简单说即数据库系统的特点为高共享、低冗余、独立性高、具有完整性等。
将实体-联系模型转换为关系模型时,实体之间多对多联系在关系模型中的实现方式是( )
- A 建立新的关系
- B 建立新的属性
- C 增加新的关键字
- D 建立新的实体
实体联系模型(Entity Relationship Mode1),是一种以直观的图示化方式描述实体(集)及其之间联系的语义模型,所以也称为实体-联系图(Entity Relationship Diagram,E-R 图)
在E-R图中有下面四个基本成分:
①矩形框,表示实体类型(研究问题的对象)。矩形框内写明实体名。
②菱形框,表示联系类型。菱形框内写明联系名,用无向边与有关实体连接起来,同时在无向边上注明联系类型。需要注意的是,联系也有属性,也要用无向边与联系连接起来。
③椭圆形框,表示实体类型和联系类型的属性,椭圆内写明属性名,并用无向边将其与相应的实体连接起来。
④直线,联系类型与其涉及的实体类型之间以直线连接,用来表示它们之间的联系,并在直线端部标注联系的种类( 1 : 1 或 1 : N 或 M : N)。
如每个专业设置有多门课程,某些课程可被多个专业设置。专业实体集与课程实体集之间的联系在 ER 图中表示为多对多联系
但在关系模型中,要通过中间表来表达他们的多对多关系,所以选A
关于求和函数,以下说法正确的是()
- A sum返回表达式中所有数的总和,因此只能用于数字类型的列
- B Avg返回表达式中所有数的平均值,可以用于数字型和日期型的列
- C Max和Min可以用于字符型的列
- D Count可以用于字符型的列
B:avg 不属于求和函数,不能使用日期型的列
C:max 和 min 是数值型,且也不属于求和函数
D:可以用于字符型的列 (count 中可以使用任意类型的字段),但不属于求和函数
有三个关系 R 、 S 和 T 如下: 则由关系 R 和 S 得到关系 T 的操作是( )。
- A 自然连接
- B 交
- C 除
- D 并
自然连接:如果关系 R 与 S 具有相同的属性组B,且该属性组的值相等时的连接称为自然连接,结果关系的属性集合为R的属性并上S减去属性B的属性集合。自然连接也可看作是在广义笛卡尔积RxS中选出同名属性上符合相等条件元组,再进行投影,去掉重复的同名属性,组成新的关系。
交:关系R与关系S的交运算结果由既属于R又属于S的元组(即R与S中相同的元组)组成一个新关系。如果两个关系没有相
同的元组,那么它们的交为空。
两个结果集取交集:需要两个结果集,字段相同
并:关系R与关系S的交运算结果由既属于R或属于S的元组〈即R和S的所有元组合并),删去重复元组,组成一个新关系,其结果仍为n元关系。
两个结果集,取并集:需要字段相同
除:设关系R除以关系S的结果为关系T,则T包含所有在R但不在S中的属性及其值且T的元组与s的元组的所有组合都在R中。
设有表示学生选课的三张表,学生S(学号,姓名,性别,年龄,身份证号),课程C(课号,课名),选课SC(学号,课号,成绩),则表SC的关键字(键或码) 为( )。
- A 课号,成绩
- B 学号,成绩
- C 学号,课号
- D 学号,姓名,成绩
学号是学生表S的主键,课号是课程表C的主键,所以选课表SC的关键字就应该是与前两个表能够直接联系且能唯一定义的学号和课号。使用这两个字段,创建复合主键 / 联合主键
关系数据库所采用的数据存放形式是()
- A 二维表
- B 链表
- C 网状
- D 二叉树
某关系表有:员工(部门编号,部门名称,员工编号,姓名,性别,年龄),则其主码(主键)为()。
- A 部门编号、员工编号
- B 员工编号
- C 姓名
- D 部门编号
根据业务来设计表:
(1) 员工编号:可以标识数据 (员工编号唯一,主键就是员工编号)
(2) 员工编号有重复:不同部门,有相同的员工编号:主键就是员工编号+部门编号,用这两个字段表示数据的唯一性
在使用 limit 子句时,如果没有足够的行,则:
- A MySQL会报错
- B MySQL将只返回它能返回的那么多行
- C MySQL将不会返回任何行
不属于SQL语句的是()
- A SELECT
- B CANCEL
- C UPDATE
- D ALTER
ALTER 是管理表结构的关键字
给出数据表 score(stu-id,name,math,english,Chinese), 下列语句正确的是( )
- A Select sum(math), avg(chinese) from score
- B Select *,sum(english) from score
- C Select stu-id, sum(math) from score
- D Delete * from score
SQL Server 2005 属于( )
- A 应用软件
- B 操作系统
- C 语言处理系统
- D 数据库管理系统
SQL Server 2005 是 Microsoft 公司推出的关系型数据库管理系统
设有一个数据库mydb中有一个表tb1,表中有六个字段,主键为ID,有十条记录,ID从0到9,以下代码输出结果是
- A.6
- B. 4
- C. 3
- D. 5
查询 id 小于 5 的数据,mysql_num_fields 计算的是 字段的,一共 3 个
在下面的两个关系中,职工号和部门号分别为职工关系和部门关系的主键(或称主码)职工(职工号、职工名、部门号、职务、工资) 部门(部门号、部门名、部 门人数、工资总额) 在这两个关系的属性中,只有一个属性是外键(或称外来键、外码、外来码),它是 ____
- A 职工关系的“职工号”
- B 职工关系的“部门号”
- C 部门关系的“职工号”
- D 部门关系的“部门号”
1 : m。一个职工对应一个部门,一个部门可以有多名职工
下列哪一个命令为删除 sample 数据库的 tb_ame 表()
- A delete from tb_ame
- B delete from sample.tb_ame
- C drop table tb_ame
- D drop table sample.tb_ame
C:use sample 后才可以;D:无论在哪个数据库中都可以执行成功
语句 SELECT IF(-1,5,2) 的返回值是:
- A 2
- B 6
- C -1
- D 5
if()函数的具体语法如下:IF(expr1, expr2, expr3),如果 expr1 的值为真**(boolean 值 true,或不为 0 的数值**),则返回expr2的值,否则返回expr3的值。
数据库中存在学生表S、课程表C和学生选课表SC三个表,它们的结构如下:S(S#,SN,SEX,AGE,DEPT)C(C#,CN)SC(S#,C#,GRADE)其中:S#为学号,SN 为姓名,SEX为性别,AGE为年龄,DEPT为系别,C#为课程号,CN为课程名,GRADE为成绩。请检索选修课程号为C2的学生中成绩最高的学号。( )
- A SELECT S#,SUM(GRADE)FROM SC WHERE GRADE>=60 GROUP BY S# ORDER BY 2 DESC HAVING COUNT(*)>=4 WHERE C#=“C2” AND GRADE >=(SELECT GRADE FORM S C WHERE C#=“C2”)
- B SELECT S# FORM SC WHERE C#=“C2” AND GRADE IN (SELECT GRADE FORM SC WHERE C#=“C2”)
- C SELECT S# FORM SC WHERE C#=“C2” AND GRADE NOT IN (SELECT GRADE FORM SC WHERE C#=“C2”)
- *D SELECT S# FORM SC WHERE C#=“C2” AND GRADE>=ALL (SELECT GRADE FORM SC WHERE C#=“C2”)
B:查询所有 C2 的成绩。C:查询 C2,分数不在 C2 的成绩,相矛盾,结果集为空。D:查询 C2 中,满足大于等于所有 C2 成绩的,就是最高分。
在关系型是数据库中,有两个不同的事务同时操作数据库中同一表的同一行,不会引起冲突的是:
- A 其中一个DELETE操作,一个是SELECT操作
- B 其中两个都是UPDATE
- C 其中一个是SELECT,一个是UPDATE
- D 其中一个SELECT
- E 其中一个是DELETE,另一个是UPDATE
- F 两个都是DELETE
a-f 选项:一个操作属于一个会话,另一个操作,属于另一个会话冲突;两个会话的操作,同时执行时,是否会互相影响
F:delete from 表 where id = 1 成功删除一条数据
delete from 表 where id = 1 执行成功,但没有删除任何数
计算每位学生的多学科加总成绩的 SQL 是 ____
- A select sum(score) as total,stud_name from [成绩表] (nolock)
- B select count(score) as total,stud_name from [成绩表] (nolock)
- C select sum(score) as total,stud_name from [成绩表] (nolock) group by stud_name
- D select count(score) as total,stud_name from [成绩表] (nolock) group by stud_name
以下哪个不是与Mysql服务器相互作用的通讯协议()
A TCP/IP
B UDP
C 共享内存
D Socket
B:UDP 是 无连接,不可靠的协议,用在数据库就不是一个合适的技术
TCP/IP协议:
unix socket协议:
share Memory协议:
Named Pipes协议:
公司中有多个部门和多名职员,每个职员只能属于一个部门,一个部门可以有多名职员。则实体部门和职员间的联系是()
- A 1:1联系
- B m:1联系
- C 1:m联系
- D m:n联系
设有两个事务T1,T2,其并发操作如下所示,下面评价正确的是()
步骤 T1 T2 1 读A=100 2 读A=100 3 A=A+10写回 4 A=A-10写回
A 该操作不能重复读
B 该操作不存在问题
C 该操作读"脏"数据
D 该操作丢失修改
3 -> 写回 110。4 -> 写回 90。t1 事务修改的内容已经丢失
mysql 数据库有选课表 learn(student_id int,course_id int),字段分别表示学号和课程编号, 现在想获取每个学生所选课程的个数信息,请问如下的 sql 语句正确的是()
- A select student_id,sum(course_id)from learn
- B select student_id,count(course_id)from learn group by student_id
- C select student_id,count(course_id)from learn
- D select student_id,sum(course_id)from learn group by student_id
如果事务T获得了数据项Q上的排它锁,则T对Q______。
- A 只能读不能写
- B 只能写不能读
- C 既可读又可写
- D 不能读不能写
排它锁:只能获取排它锁的事务进行操作(任何操作),其他事务不能执行任何操作
在关系模型中,实现“表示了两个关系之间的相关联系”的约束是通过()
- A 候选键
- B 主键
- C 外键
- D 超键
超键(super key):在关系中能唯—标识元组的属性集,称为关系模式的超键候选键(candidate key):
候选键:不含有多余属性的超键
假设有如下两个表:
学生(学号,姓名,性别,身份证号,教师编号)
教师(教师编号,姓名,工资)
超键:
由超键的定义可知,学生表中含有学号或者身份证号的任意组合都为此表的超键。学号或身份证号都可以唯一定位一个学生,但是加上姓名之类可以可以,如:(学号)、(学号,姓名)、(身份证号,性别)等。
候选键:
候选键属于超键,它是最小的超键,就是说如果再去掉候选键中的任何一个属性它就不再是超键了。学生表中的候选键为:(学号)、(身份证号)。
学生关系模式S(S#,Sname,Sex,Age),S的属性分别表示学生的学号、姓名、性别、年龄。要在表S中删除一个属性“年龄”,可选用的SQL语句是()
- A ALTER TABLE S DROP Age
- B ALTER TABLE S ‘Age’
- C UPDATE S Age
- D DELETE Age from S
修改表结构的关键字都是 alter tab1e 表名,再跟具体修改的语句,如:
添加表字段
alter table table_name add 字段名称字段类型
删除表字段
alter table table_rame drop 字段名称
修改表字段
alter tab1e table_name change 旧字段名称新字段名称字段类型
alter table table_name modify 字段名称宁段类型
一个查询语句执行后显示的结果为: 1班 80 2班 75 3班 NULL ,则最有可能的查询语句是()
- A SELECT AVG(成绩) FROM 成绩表 WHERE class<=3
- B SELECT AVG(成绩) FROM 成绩表 WHERE class<=3 GROUP BY class
- C SELECT AVG(成绩) FROM 成绩表 WHERE class<=3 order by class
- D SELECT AVG(成绩) FROM 成绩表 HAVING class <=3 GROUP BY class
下列sql语句中哪条语句可为用户zhangsan 分配数据库userdb 表userinfo的查询和插入数据权限()。
- A grant select,insert on userdb.userinfo to’zhangsan’@‘localhost’
- B grant’zhangsan’@'localhost’to select,insert for userdb.userinfo
- C grant select,insert on userdb.userinfo for’zhangsan’@‘localhost’
- D grant’zhangsan’@'localhost’to userdb.userinfo on select,insert
常用的管理权限的命令有:
本机访问:localhost。允许任何地址访问:%
下列对于数据库索引的说法一定是错误的()
- A 索引可以提升查询,分组和排序的性能
- B 索引不会影响表的更新、插入和删除操作的效率
- C 全表扫描不一定比使用索引的执行效率低
- D 对于只有很少数据值的列,不应该创建索引
A:创建索引:根据一列,或多列来创建;查询条件依赖的列,分组列,排序列,都可以使用这些列上的索引
B:数据量越大,数据更新的操作(插入,修改,删除)对索引的效率影响越大
C:数据量很少,全表打描 [一行一行地遍历],可能比根据索引来检索数据更快
D:性别,两个:男,女。索引就不太有必要〔索引后续的维护效率会比较低)
下面哪个SQL命令用来向表中添加列()
- A MODIFY TABLE TableName ADD COLUMN ColumnName
- B MODIFY TABLE TableName ADD ColumnName
- C ALTER TABLE TableName ADD COLUMN ColumnName
- D ALTER TABLE TableName ADD ColumnName Type
有订单表orders,包含字段用户信息userid,字段产品信息productid,以下语句能够返回至少被订购过两次的productid?
- A select productid from orders where count(productid)>1
- B select productid from orders where max(productid)>1
- C select productid from orders where having count(productid)>1 group by productid
- D select productid from orders group by productid having count(productid)>1
D:count是分组前,相同的分组字段productid,合并时,可以计算行数(相同produclid,合并,每一个的行数)
在手机开发中常用的数据库是 ___
- A sqlLite
- B Oracle
- C Sql Server
- D Db23
sqlLite 内存数据库,安卓手机使用最多的。其余三个是企业级,大型数据库
下列哪个特性与此事相关:已落实的事务会保证所有操作均已完成,并且在事务回滚中,所有操作产生的影响均已得到恢复?
- A 隔离性
- B 原子性
- C 一致性
- D 持久性
已落实的事务会保证所有操作均已完成:所有操作全部执行成功。
在事务回滚中,所有操作产生的影响均已得到恢复:所有操作全部不执行
隔离性:并发执行时,互不干扰。原子性:所以执行成功,或不执行。一致性:操作时保证数据的完整性。持久性:执行成功,数据持久化存储起来了,数据写入到硬盘。
athletes 表包含运动员姓名,年纪和代表国家。下面哪个查询可以找出代表每个国家最年轻的运动员情况?
- A SELECT name, country, age FROM athletes WHERE (country, age) IN (SELECT country, min(age) FROM athletes GROUP BY country)
- B SELECT name, country, age FROM athletes WHERE (country, age) IN (SELECT min(age), country FROM athletes GROUP BY country)
- C SELECT name, country, age FROM athletes WHERE (country, age) IN (SELECT country, min(age) FROM athletes) GROUP BY country
- D SELECT name, country, age FROM athletes WHERE age IN (SELECT country, min(age) FROM athletes GROUP BY country)
D:字段in (子查询)。字段可以有 1个 或 多个,但字段需要和 子查询结果集 字段 的数量,顺序一致。前面 3 个,后面 2 个
B:同样,(country, age) 和 min(age), country 对不上
C:min(age) FROM athletes,查询的是,所有国家最年轻的运动员,只有一条信息,而 A 是分组查每个国家
执行以下 SQL ,下面哪个名字会被查询出来()
SELECT FirstName FROM StaffList WHERE FirstName LIKE’_A%’
- A Allen
- B CLARK
- C JACKSON
- D David
数据库中可以设置是否大小写敏感
mysql数据库有选课表learn(student_id int,course_id int),字段分别表示学号和课程编号,现在想获取每个学生所选课程的个数信息,请问如下的sql语句正确的是
A select student_id,sum(course_id)from learn
B select student_id,count(course_id)from learn group by student_id
C select student_id,count(course_id)from learn
D select student_id,sum(course_id)from learn group by student_id
如下SQL语句中,可能返回null值。 (1) select count(*) from t1; (2) select max(col1) from t1; (3) select concat(‘max=’,max(col1)) from t1;
- A (1)可能,(2)和(3)不可能
- B (2)可能,(1)和(3)不可能
- C (3)可能,(1)和(2)不可能
- D (1)不可能,(2)和(3)可能
- E 都不可能
- F 都可能
count(*):一定可以返回数值,没有数据,返回 0。
max:t1 表中没有数据,或者 col 字段都是 null,会返回 null。
concat:字符串拼接函数,数据库中,不能用 +
拼接字符串。如果拼接的字符串中有一个是 null,结果就是 null
下列关于数据库特点的说法中正确的是( )
- A 数据能共享且独立性高
- B 数据能共享但数据冗余很高
- C 能保证数据完整性但降低了安全性
- D 数据独立性高但不能实现共享
通过关联,就可以共享。逻辑上和物理上,独立性高
在关系表中,属性值必须是另一个表主键的有效值或空值,这样的属性是( )
- A 外键
- B 候选键
- C 主键
默认创建的外键是严格模式 (必须在主表中,关联的键有该数据),其他模式其实外键值可以是空。候选键:可以标识数据唯一性的最小集
以下哪一句从表TABLE_NAME中提取前10条记录?
- A select * from TABLE_NAME where rowcount=10
- B select TOP 10 * from TABLE_NAME
- C select TOP of 10 * from TABLE_NAME
- D select * from TABLE_NAME where rowcount<=10
top 关键字 是 sql server 中的关键字,同于求 前 n 条数据。select top n 查询字段 from...
,如果要查前 m 到前 n 条,要写子查询。
查找 student表中所有电话号码(列名:telephone)的第一位为8或6,第三位为0的电话号码
- A SELECT telephone FROM student WHERE telephone LIKE ‘[8,6]%0*’
- B SELECT telephone FROM student WHERE telephone LIKE ‘(8,6)*0%’
- C SELECT telephone FROM student WHERE telephone LIKE ‘[8,6]_0%’
- D SELECT telephone FROM student WHERE telephone LIKE ‘[8,6]_0*’
数据库有一个试卷表,希望找出试卷平均得分小于 90 的所有试卷( )
- A SELECT * FROM paper group by score having sum(score) < 90;
- B SELECT * FROM paper group by score having avg(score) < 90;
- C SELECT * FROM paper group by score having max(score) < 90;
- D SELECT * FROM paper group by score having mid(score) < 90;
电话号码表t_phonebook中含有100万条数据,其中号码字段PhoneNo上创建了唯一索引,且电话号码全部由数字组成,要统计号码头为321的电话号码的数量, 下面写法执行速度最慢的是___
- A select count(*) from t_phonebook where phoneno >= ‘321’ and phoneno < ‘321A’ *
- B select count() from t_phonebook where phoneno like ‘321%’
- C select count(*) from t_phonebook where substr(phoneno,1,3) = ‘321’
- D 都一样快
A:PhoneNo 是数字组成(使用数值数据类型),和字符串可以比较,但是会进行类型转换 (有点耗时)。
B:模糊匹配:最开始xxx的匹配,可以使用
C:使用函数,不会再使用索引,全部数据扫描遍历,函数本身的执行,也需要耗时
数据库事务的 4 个特性是:原子性、一致性、()、隔离性。
- A 只读性
- B 封装性
- C 持续性 / 持久性
- D 恢复性
以下不是RDBMS的是()
- A mysql
- B postgreSql
- C oracle
- D hadoop
RDBMS 是关系型数据库。hadoop 是大数据的数据库,不是关系型
下列关于线性链表的叙述中,正确的是( )。
- A 各数据结点的存储空间可以不连续,但它们的存储顺序与逻辑顺序必须一致
- B 各数据结点的存储顺序与逻辑顺序可以不一致,但它们的存储空间必须连续
- C 进行插入与删除时,不需要移动表中的元素
- D 以上说法均不正确
下列数据结构中,不能采用顺序存储结构的是( )
- A 非完全二叉树
- B 堆
- C 队列
- D 栈
二叉树中,只有完全二叉树可以使用顺序表存储,完全二叉树元素都靠左排序。非完全二叉树只能采用链式存储 Node left,Noderight
递归函数最终会结束,那么这个函数一定?
- A 使用了局部变量
- B 有一个分支不调用自身
- C 使用了全局变量或者使用了一个或多个参数
- D 没有循环调用
直接排除AD,注意力集中在B和C。 B肯定是对的,只有一次循环满足某个条件,不调用自己就返回,递归才会一层一层向上返回。 那么C呢,想一下,全局变量和参数确实可以用来控制递归的结束与否。 该不该选C呢?再仔细看一下题目(说实话,我很讨厌这种文字游戏),“这个函数一定…“,所以,问题集中在,是否是一定会使用这两种方式呢? 显然不是 的。 除了C中提到的两种情况外,还有如下控制递归的方式: 1. 局部静态变量是可以控制递归函数最终结束的 2. 可能通过异常来控制递归的结束。 3. 可以利用BIOS或OS的一些数据或一些标准库的全局值来控制递归过程的 终止。 4. 可以把一些数据写入到BIOS或OS的系统数据区,也可以把数据写入到一个文件中,以此来控制递归函数的终止。 所以,答案为B
已知二叉树后序遍历序列是bfegcda,中序遍历序列是badefcg,它的前序遍历序列是:
- A abcdefg
- B abdcefg
- C adbcfeg
- D abecdfg
以下序列不是堆的是()
- A (100,85,98,77,80,60,82,40,20,10,66)
- B (100,98,85,82,80,77,66,60,40,20,10)
- C (10,20,40,60,66,77,80,82,85,98,100)
- D (100,85,40,77,80,60,66,98,82,10,20)
设有一组记录的关键字为 {19,14,23,1,68,20,84,27,55,11,10,79}, 用链地址法构造哈希表,哈希函数为H(key)=key MOD 13,哈希地址为1的链中有()个记录
- A 1
- B 2
- C 3
- D 4
若栈采用顺序存储方式存储,现两栈共享空间V[1…m],top[i]代表第i个栈( i =1,2)栈顶,栈1的底在v[1],栈2的底在V[m],则栈满的条件是( )。
- A top[1]+top[2]=m
- B top[1]+1=top[2]
- C top[2]-top[1]|=0
- D top[1]=top[2]
从前有座山,山里有座庙,庙里有个老和尚,再给小和尚讲故事,故事内容是:从前有座山,山里有座庙,庙里有个老和尚,再给小和尚讲故事,故事内容是:从前 有座山,山里有座庙,庙里有个老和尚,再给小和尚讲故事,故事内容是……描述的是()
- A 贪心
- B 回溯
- C 穷举
- D 分治
- E 递归
某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( )
- A 不存在这样的二叉树
- B 200
- C 198
- D 199
对任何一棵二叉树,度为 0 的结点(即叶子结点)总是比度为 2 的结点多一个。题目中度为 2 的结点为 199 个,则叶子结点为 199+1=200 。
某二叉树的前序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为( )
- A ABCDEF
- B BCDEFA
- C FEDCBA
- D DEFABC
二叉树的中序遍历序列和前序遍历序列均为 ABCDEF ,可知该树只有右子树结点,没有左子树结点
初始序列为1 8 6 2 5 4 7 3一组数采用堆排序,当建堆(小根堆)完毕时,堆所对应的二叉树中序遍历序列为:()
- A 8 3 2 5 1 6 4 7
- B 3 2 8 5 1 4 6 7
- C 3 8 2 5 1 6 7 4
- D 8 2 3 5 1 4 7 6
从最后一个非叶子结点开始进行元素 siftDown 操作
解决散列法中出现冲突问题常采用的方法是____。
- A 数字分析法、除余法、平方取中法
- B 数字分析法、除余法、线性探测法
- C 数字分析法、线性探测法、多重散列法
- D 线性探测法、多重散列法、链地址法
以下哪种排序算法对(1,3,2,4,5,6,7,8,9)进行的排序最快?
- A 冒泡 (优化过的)
- B 快排
- C 归并
- D 堆排
以下数据结构中,()是非线性数据结构
- A 树
- B 字符串
- C 队
- D 栈
设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5,e6依次压入栈S,一个元素出栈后即进入队列Q,若出队列的顺序为e2,e4,e3,e6,e5,e1则栈S的容量要求 最小值为
- A 2
- B 3
- C 4
- D 5
在具有 2n 个结点的完全二叉树中,叶子结点个数为( )
- A n
- B n+1
- C n-1
- D n/2
当完全二叉树的结点个数为偶数时,则度为 1 的结点个数为 1
任意二叉树中,度为 0 的节点,比度为 2 的节点多一个,设度为 2 的节点个数为 x,度为 0 的节点个数为 x + 1
2n = x + x + 1 + 1 => x = n
下列叙述中错误的是( )
- A 二叉链表是二叉树的存储结构
- B 循环链表是循环队列的存储结构
- C 栈是线性结构
- D 循环队列是队列的存储结构
B 应该是数组:循环链表是用不连续的存储单元存储数据,它有一个表头结点,队头指针指向表头结点,最后一个结点的指针域指向表头结点。
循环队列是队列的一种顺序存储结构,用队尾指针 rear 指向队列中的队尾元素,用排头指针 front 指向排头元素的前一个位置。
下述二叉树中,哪一种满足性质:从任一结点出发到根的路径上所经过的结点序列按其关键字有序()
- A 二叉排序树
- B 哈夫曼树
- C AVL树
- D 堆
哈夫曼树:带权值的树 (与元素大小顺序无关)
AVL树:平衡二叉搜索树,根节点左边都小于根,右边都大于根
// 10
// 5
// 8
//从 8 出发到 10:8 5 10,不是有序
堆:如果是大根堆,根大于左右,从最大堆的任意结点出发走到根节点都是一个递增序列
为提高散列(Hash)表的查找效率,可以采取的正确措施是( )。
Ⅰ.增大装填(载)因子
Ⅱ.设计冲突(碰撞)少的散列函数
Ⅲ.处理冲突(碰撞)时避免产生聚集(堆积)现象
- A 仅Ⅰ
- B 仅Ⅱ
- C 仅Ⅰ、 Ⅱ
- D 仅Ⅱ、 Ⅲ
我们通过降低负载因子来变相的降低冲突率。Ⅰ:增加元素冲突,查找变慢
将整数数组(7-6-3-5-4-1-2)按照堆排序的方式原地进行升序排列,请问在第一轮排序结束之后,数组的顺序是_____。
- A 2-6-3-5-4-1-7
- B 6-2-3-5-4-1-7
- C 6-5-3-2-4-1-7
- D 1-5-3-2-4-6-7
- E 5-4-3-2-1-6-7
- F 5-1-3-2-4-6-7
题中已经是大根堆,swap(0, arr, length - 1); 得到最大值 7,然后继续在剩下的元素中调整为最大堆,从最后一个节点开始调整,重复上述过程
下列各排序法中,最坏情况下的时间复杂度最低的是( )
- A 希尔排序
- B 快速排序
- C 堆排序
- D 冒泡排序
最坏情况下:插入排序的优化 O(N^2),至少比 O(nlogn) 大
当出现大量重复元素或者数组几乎有序时,递归树退化为链表,O(N^2)
堆排序是一个非常稳定的 O(nlogn)
冒泡排序是 O(N^2)
下列数据结构具有记忆功能的是?
- A 队列
- B 循环队列
- C 栈
- D 顺序表
浏览器的回退功能,文本编译器的撤销操作,都属于记忆功能。栈的前进后出 LIFO 特性,A 函数调用 B 函数,B 函数调用 C 函数
循环两列放在一维数组A[0…M-1]中,end1指向队头元素,end2指向队尾元素的后一个位置。假设队列两端均可进行入队和出队操作,队列中最多能容纳M-1个元 素。初始时为空,下列判断队空和队满的条件中,正确的是 ()
- A 队空:end1==end2; 队满:end1==(end2+1)modM
- B 队空:end1==end2; 队满:end2==(end1+1)mod(M-1)
- C 队空:end2==(end1+1)modM ; 队满:end1==(end2+1)modM
- D 队空:end1==(end2+1)modM; 队满:end2==(end1+1)mod(M-1)
对递归程序的优化的一般的手段为()
- A 尾递归优化
- B 循环优化
- C 堆栈优化
- D 停止值优化
尾递归优化:例如快速排序 和 归并排序,在递归的终止条件,left 是区间的最左侧,right 是区间的最右侧,终止条件:left >= right。在递归终止条件处优化,当区间个数较小时,采用插入排序优化,(right - left <= 15),来减少递归
有 1000 个无序的整数,希望使用最快的方式找出前 50 个最大的,最佳的选择是( )
- A 冒泡排序
- B 基数排序
- C 堆排序
- D 快速排序
topK 问题,堆 / 优先级队列
以下数据结构说法,错误的是___?
- A 红黑树插入操作的平均时间复杂度为O(logn),最坏时间复杂度为O(logn)
- B B+树插入操作的平均时间复杂度为O(logn),最坏时间复杂度为O(logn)
- C Hash表插入操作的平均时间复杂度为O(logn),最坏时间复杂度为O(n)
- D 排序链表插入操作的平均时间复杂度为O(n),最坏时间复杂度为O(n)
数据结构 | search | insert | delete |
---|---|---|---|
数组 | O(n),有序数组折半查找 是O(lgn) | O(n) | O(n) |
双向链表 | O(n) | O(1) | O(1) |
排序二叉树 | O(lgn) | O(lgn) | O(lgn) |
哈希表(n与槽数m成 正比) | O(1) | O(1) | O(1) |
将两个各有n个元素的有序表归并成一个有序表,最少的比较次数是()
- A 2n
- B 2n-1
- C n-1
- D n
两个有序的子区间个数都为 n,最好的情况为第二个区间都比第一个区间大,只需要比较n次即可
下列排序法中,每经过一次元素的交换会产生新的逆序的是( )
- A 快速排序
- B 冒泡排序
- C 简单插入排序
- D 简单选择排序
在数据元素的序列中,对于某个元素,如果其后存在一个元素小于它,则称之为存在一个逆序。
冒泡排序:只交换相邻元素,但不是每次移动都产生新的逆序,[交换相邻的元素,不一定会产生逆序对]。
快速排序:每一次交换移动都会产生新的逆序,因为当不会有新的逆序产生时,本轮比较结束,[一定会产生逆序]。
简单插入排序:每一次比较后最多移掉一个逆序,[减少逆序对]。
简单选择排序:基本思想是先从所有 n 个待排序的数据元素中选择最小的元素,将该元素与第一个元素交换,再从剩下的 n - 1 个元素中选出最小的元素与第 2 个元素交换,这样做不会产生逆序,[减少逆序对]。
在双向循环链表中,在p指针所指的节点后插入一个指针q所指向的新节点,修改指针的操作是____。
- A p->next=q;q->prior=p;p->next->prior=q;q->next=q;
- B p->next=q;p->next->prior=q;q->prior=p;q->next=p->next;
- C q->prior=p;q->next=p->next;p->next->prior=q;p->next=q;
- D q->next=p->next;q->prior=;p->next=q;p->next=q;
采用递归方式对顺序表进行快速排序,下列关于递归次数的叙述中,正确的是()
- A 递归次数与初始数据的排列次序无关
- B 每次划分后,先处理较长的分区可以减少递归次数
- C 每次划分后,先处理较短的分区可以减少递归次数
- D 递归次数与每次划分后得到的分区处理顺序无关
一棵完全二叉树第六层有9个叶结点(根为第一层),则结点个数最多有()
- A: 111
- B: 109
- C: 107
- D: 112
第六层有 9 个叶结点 ,说明有第七层,而第七层中,少了 第 6 层 9 个的叶子结点,第一层到第七层:1 + 2 + 4 + 8 + 16 + 32 + 2(32-9) = 63 + 2*23 = 109
已知关键字序列5,8,12,19,28,20,15,22是最小堆,插入关键字3,调整后得到的最小堆是()
- A 3,8,12,5,20,15,22,28,19
- B 3,5,12,19,20,15,22,8,28
- C 3,12,5,8,28,20,15,22,19
- D 3,5,12,8,28,20,15,22,19
已知一个线性表(38,25,74,63,52,48),假定采用散列函数h(key) = key%7 计算散列地址,并散列存储在散列表A【0…6】中,若采用线性探测方法解 决冲突,则在该散列表上进行等概率成功查找的平均查找长度为
- A 1.5
- B 1.7
- C 2.0
- D 2.3
以30为基准,设一组初始记录关键字序列为 (30,15,40,28,50,10,70), 则第一趟快速排序结果为()
- A 10,28,15,30,50,40,70
- B 10,15,28,30,50,40,70
- C 10,28,15,30,40,50,70
- D 10,15,28,30,40,50,70
30, 15, 40, 28 ->
30, 15, 28, 40, 50, 10 ->
30, 15, 28, 10, 50, 40, 70
10, 15, 28, 30, 50, 40, 70
一棵二叉树的先序遍历为EFHIGJK,中序遍历为HFIEJKG,则后序遍历为( )
- A HIFJKGE
- B FHIJKGE
- C HIFGJKE
- D HIFKJGE
// 下面选项中,哪些是interface中合法方法定义?()
A public void main(String [] args);
B private int getSum();
C boolean setFlag(Boolean [] test);
D public float get(int x);
选择 ACD,B 不是能是 public
下列有关JAVA异常处理的叙述中正确的是()
A finally是为确保一段代码不管是否捕获异常都会被执行的一段代码
B throws是用来声明一个成员方法可能抛出的各种非运行异常情况
C final用于可以声明属性和方法,分别表示属性的不可变及方法的不可继承
D throw是用来明确地抛出一个异常情况
final
用于可以声明属性和方法,分别表示属性的不可变及方法的不可重写
下列关于构造方法的叙述中,错误的是()
A java语言规定构造方法名与类名必须相同
B java语言规定构造方法没有返回值,但不同void声明
*C java语言规定构造方法不可以重载
*D java语言规定构造方法只能通过new自动调用
可以再子类中通过 super()
调佣构造方法
下面哪些赋值语句是正确的()
A long test=012
B float f=-412
C int other =(int)true
D double d=0x12345678
E byte b=128
// 在 Java 中下面 Class 的声明哪些是错误的?
*A. public abstract final class Test { abstract void method(); }
*B. public abstract class Test { abstract final void method(); }
*C. public abstract class Test { abstract void method() { } }
D. public class Test { final void method() { } }
abstract 不能有 final,抽象方法不能有方法体
链接:组队竞赛
牛牛举办了一次编程比赛,参加比赛的有3*n个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。
例如:
一个队伍三个队员的水平值分别是3,3,3.那么队伍的水平值是3
一个队伍三个队员的水平值分别是3,2,3.那么队伍的水平值是3
一个队伍三个队员的水平值分别是1,5,2.那么队伍的水平值是2
为了让比赛更有看点,牛牛想安排队伍使所有队伍的水平值总和最大。
如样例所示:
如果牛牛把6个队员划分到两个队伍
如果方案为:
team1:{1,2,5}, team2:{5,5,8}, 这时候水平值总和为7.
而如果方案为:
team1:{2,5,8}, team2:{1,5,5}, 这时候水平值总和为10.
没有比总和为10更大的方案,所以输出10.
输入描述:
输入的第一行为一个正整数n(1 ≤ n ≤ 10^5)
第二行包括3*n个整数a_i(1 ≤ a_i ≤ 10^9),表示每个参赛选手的水平值.
输出描述:
输出一个整数表示所有队伍的水平值总和最大值.
输入
2
5 2 8 5 1 5
输出
10
import java.util.*;
public class Main {
// len - 2 * (i + 1)
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextInt()) {
int n = scanner.nextInt();
int[] array = new int[3 * n];
for (int i = 0; i < 3 * n; i++) {
array[i] = scanner.nextInt();
}
Arrays.sort(array);
long sum = 0;
for (int i = 0; i < n; i++) {
sum += array[array.length - 2 * (i + 1)];
}
System.out.println(sum);
}
}
public static void main1(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextInt()) {
int n = scanner.nextInt();
int[] array = new int[3 * n];
for (int i = 0; i < 3 * n; i++) {
array[i] = scanner.nextInt();
}
Arrays.sort(array);
if (n == 3) {
System.out.println(array[1]);
} else {
int teams = n;
int right = 3 * n - 2;
long ans = 0; // 溢出
while (teams > 0) {
ans += array[right];
right -= 2;
teams--;
}
System.out.println(ans);
}
}
}
}
链接:倒置字符串
将一句话的单词进行倒置,标点不倒置。比如 I like beijing. 经过函数后变为:beijing. like I
输入描述:
每个测试输入包含1个测试用例: I like beijing. 输入用例长度不超过100
输出描述:
依次输出倒置之后的字符串,以空格分割
输入
I like beijing.
输出
beijing. like I
// 空格分割 从后往前输出
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
String[] ret = str.split(" ");
for(int i = ret.length - 1; i >= 0; i--) {
if(i == 0) {
System.out.print(ret[i]);
} else {
System.out.print(ret[i] + " ");
}
}
}
}
// 整体逆置 分别逆置
import java.util.*;
public class Main {
public static void reverse(char[] ch, int i, int j) {
while (i < j) {
char tmp = ch[i];
ch[i] = ch[j];
ch[j] = tmp;
i++;
j--;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
char[] ch = str.toCharArray();
int len = ch.length;
// 1、整体逆置
reverse(ch, 0, len - 1);
int i = 0; // 遍历
while (i < len) {
int j = i;
while (j < len && ch[j] != ' ') {
j++; // 找单词结束位置
}
if(j < len) {
reverse(ch, i, j - 1);
i = j + 1; // 下一个单词
} else {
reverse(ch, i, j - 1); // 一个字符
i = j;
}
}
// System.out.println(Arrays.toString(ch)); // [ , f, l, y, !, , c, a, n, i]
String ans = new String(ch);
System.out.println(ans);
}
}
牛牛定义排序子序列为一个数组中一段连续的子序列,并且这段子序列是非递增或者非递减排序的。牛牛有一个长度为n的整数数组A,他现在有一个任务是把数组A分为若干段排序子序列,牛牛想知道他最少可以把这个数组分为几段排序子序列.
如样例所示,牛牛可以把数组A划分为[1,2,3]和[2,2,1]两个排序子序列,至少需要划分为2个排序子序列,所以输出2
输入描述:
输入的第一行为一个正整数n(1 ≤ n ≤ 10^5)
第二行包括n个整数A_i(1 ≤ A_i ≤ 10^9),表示数组A的每个数字。
输出描述:
输出一个整数表示牛牛可以将A最少划分为多少段排序子序列
输入
6
1 2 3 2 2 1
输出
2
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] array = new int[n];
for(int i = 0; i < n; i++) {
array[i] = scan.nextInt();
}
int count = 0;
int i = 0;
while(i < n - 1) {
if(i < n - 1 && array[i] > array[i + 1]) {
while(i < n - 1 && array[i] > array[i + 1]) {
i++;
}
count++;
i++; // 下一个序列
} else if (i < n - 1 && array[i] == array[i + 1]) {
while(i < n - 1 && array[i] == array[i + 1]) {
i++;
}
}else if(i < n - 1 && array[i] < array[i + 1]) {
while(i < n - 1 && array[i] < array[i + 1]) {
i++; // 非递增:包含相等 1 2 2 或 2 2 1 相等跳过
}
count++;
i++; // 下一个序列
}
}
if(i == n - 1) { // 最后一个字母
// 因为 i < n - 1,正常分 i = n
// 如果相等 跳过 只剩最后一个字母 或分完只剩最后一个字母
count++;
}
System.out.println(count == 0 ? count + 1 : count);
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] array = new int[n + 1]; // 越界 数组长度 n + 1
for(int i = 0; i < n; i++) {
array[i] = scan.nextInt();
}
int count = 0;
int i = 0;
while (i < n) {
if(array[i] < array[i + 1]) {
while(i < n && array[i] < array[i + 1]) {
i++;
}
count++;
i++;
} else if (array[i] == array[i + 1]) {
i++;
} else {
while(i < n && array[i] > array[i + 1]) {
i++;
}
count++;
i++;
}
}
System.out.println(count);
}
}
链接:字符串中找出连续最长的数字串
读入一个字符串str,输出字符串str中的连续最长的数字串
输入描述:
个测试输入包含1个测试用例,一个字符串str,长度不超过255。
输出描述:
在一行内输出str中里连续最长的数字串。
输入
abcd12345ed125ss123456789
输出
123456789
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
String cur = "";
String ret = "";
int i = 0;
for (; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch >= '0' && ch <= '9') {
cur = cur + ch + ""; // 放到 cur 上
} else {
if (cur.length() > ret.length()) {
ret = cur; // ret 放长度最大数字串
} else {
cur = "";
}
}
}
// 如果结尾是数字,且是最大串,循环结束,没有更新到 ret 上,得到的结果就是最大串
if (i == str.length() && cur.length() > ret.length()) {
ret = cur;
}
System.out.println(ret);
}
public static void main2(String[] args) {
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
int max = 0;
int count = 0;
int end = 0;
for (int i = 0; i < str.length(); i++) {
if(Character.isDigit(str.charAt(i))) {
count++;
if(count > max) {
max = count; // 最长串的长度
end = i; // 记录最长串的最后位置
}
} else {
count = 0;
}
}
System.out.println(str.substring(end - max + 1, end + 1));
}
public static void main1(String[] args) {
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
for(int i = 0; i < str.length(); i++) {
if(!Character.isDigit(str.charAt(i))) { // 不是数字 清空短的
if(sb1.length() > sb2.length()) {
sb2.delete(0, sb2.length());
} else {
sb1.delete(0, sb1.length());
}
} else {
// 谁不为空 加入下一个数字串
if(sb1.length() == 0){
while(i < str.length() && Character.isDigit(str.charAt(i))) {
sb1.append(str.charAt(i));
i++;
}
i--;
} else {
while(i < str.length() && Character.isDigit(str.charAt(i))) {
sb2.append((str.charAt(i)));
i++;
}
i--; // for 循环 i 已经每次++ 避免跳过了
}
}
}
System.out.println(sb1.length() > sb2.length() ? sb1.toString() : sb2.toString());
}
}
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:n≤50000n \le 50000n≤50000,数组中元素的值 0≤val≤100000 \le val \le 100000≤val≤10000
要求:空间复杂度:O(1),时间复杂度 O(n)
输入描述:
保证数组输入非空,且保证有解
输入
[1,2,3,2,2,2,5,4,2]
输出
2
与此题一样:leetcode 169. 多数元素
如果题目没有指定,非空和一定有解,此时就要再次遍历判断
思路一:排序
找到中间的数字 X,再次遍历这个数组看一下这个X,出现了多少次
如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众教
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if (array == null || array.length == 0) {
return 0;
}
int result = array[0];
int times = 1;
for (int i = 1; i < array.length; i++) {
if (times != 0) {
if (array[i] != result) {
times--;
} else {
times++;
}
} else {
result = array[i];
times = 1;
}
}
times = 0;
for (int i = 0; i < array.length; i++) {
if (result == array[i]) {
times++;
}
}
if(times > array.length / 2) {
return times;
}
return 0;
}
public int MoreThanHalfNum_Solution1(int [] array) {
if (array == null || array.length == 0) {
return 0;
}
Arrays.sort(array);
int len = array.length;
int midNum = array[len / 2];
int cnt = 0;
for (int i = 0; i < len; i++) {
if(array[i] == midNum) {
cnt++;
}
}
if (cnt > len / 2) {
return midNum;
}
return 0;
}
}
A,B,C三个人是好朋友,每个人手里都有一些糖果,我们不知道他们每个人手上具体有多少个糖果,但是我们知道以下的信息:
A - B, B - C, A + B, B + C. 这四个数值.每个字母代表每个人所拥有的糖果数.
现在需要通过这四个数值计算出每个人手里有多少个糖果,即A,B,C。这里保证最多只有一组整数A,B,C满足所有题设条件。
输入描述:
输入为一行,一共4个整数,分别为A - B,B - C,A + B,B + C,用空格隔开。 范围均在-30到30之间(闭区间)。
输出描述:
输出为一行,如果存在满足的整数A,B,C则按顺序输出A,B,C,用空格隔开,行末无空格。 如果不存在这样的整数A,B,C,则输出No
输入
1 -2 3 4
输出
2 1 3
解法一:
① A - B = a
② B - C = b
③ A + B = c
④ B + C = d
A = (a + c) / 2; ① + ②
B1 = (b + d) / 2; ② + ④
B2 = (c - a) / 2; ③ - ①
C = (d - b) / 2; ④ - ③
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int b = scanner.nextInt();
int c = scanner.nextInt();
int d = scanner.nextInt();
int A = (a + c) / 2;
int B1 = (b + d) / 2;
int B2 = (c - a) / 2;
int C = (d - b) / 2;
if (B1 != B2) {
System.out.println("No");
} else {
System.out.println(A + " " + B1 + " " + C);
}
}
}
解法一:
// a-b b-c a+b b+c
import java.util.*;
public class Main {
public static boolean isABC(int a, int b, int c, int n1, int n2, int n3, int n4) {
if(a-b == n1 && b-c == n2 && a+b == n3 && b+c == n4) {
return true;
}
return false;
}
public static void main(String[] args) {
// a-b b-c a+b b+c
Scanner scanner = new Scanner(System.in);
int[] array = new int[4];
for(int i = 0; i < 4; i++) {
array[i] = scanner.nextInt();
}
int n1 = array[0], n2 = array[1], n3 = array[2], n4 = array[3];
int a = (n1 + n3) / 2;
int b = (n2 + n4) / 2;
int c = n4 - b;
if(isABC(a, b, c, n1, n2, n3, n4)) {
System.out.println(a + " " + b + " " + c);
} else if (isABC(b, c, a, n1, n2, n3, n4)) {
System.out.println(b + " " + c + " " + a);
} else if (isABC(c, a, b, n1, n2, n3, n4)) {
System.out.println(c + " " + a + " " + b);
} else {
System.out.println("No");
}
}
}
给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数
输入描述:
输入为一行,M(32位整数)、N(2 ≤ N ≤ 16),以空格隔开。
输出描述:
为每个测试实例输出转换后的数,每个输出占一行。如果N大于9,则对应的数字规则参考16进制(比如,10用A表示,等等)
输入
7 2
输出
111
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
StringBuilder sb = new StringBuilder();
int m = scanner.nextInt();
int n = scanner.nextInt();
// m 等于 0
if(m == 0) {
System.out.println(0);
return;
}
// m 是负数
Boolean flg = false;
if(m < 0) {
flg = true;
m = -m;
}
String str = "ABCDEF";
while (m > 0) {
int tmp = m % n;
if (tmp >= 10) { // 十六进制
sb.append(str.charAt(tmp - 10));
} else {
sb.append(tmp);
}
m /= n;
}
if(flg) {
sb.append("-");
}
System.out.println(sb.reverse().toString());
}
}
链接
一个数组有 N 个元素,求连续子数组的最大和。 例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3
输入描述:
输入为两行。 第一行一个整数n(1 <= n <= 100000),表示一共有n个元素 第二行为n个数,即每个元素,每个整数都在32位int范围内。以空格分隔。
输出描述:
所有连续子数组中和最大的值。
输入
3
-1 2 1
输出
3
【题目解析】:
本题是一个经典的动规问题,简称dp问题,但是不要害怕,这个问题是非常简单的dp问题,而且经常会考察,
所以大家一定要把这个题做会。本题题意很简单,就是求哪一段的子数组的和最大。
状态方程式: max( dp[ i ] ) = getMax( max( dp[ i -1 ] ) + arr[ i ], arr[ i ] )
dp[i]
就是以数组下标为 i
的数做为结尾的最大子序列和,注意是以 i
为结尾,
比如说现在有一个数组 {6, -3, -2, 7, -15, 1, 2, 2},dp[2]
就是以 -2
为结尾的,那么显然 dp[3]
的最大值就是 1 咯(6,-3,-2);dp[3]
要以 7 结尾,那么以 7 结尾的子序列最大和就是 8(6,-3,-2,7)。
现在我们开始细细品一下上面这个递推式,求 dp[i]
的时候是不是有两种可能,要么就是像上面的 dp[3]
一样,dp[2]
求出来是1了,再加上自己 array[3]
是最大的,那么还有一种可能就是说如果 dp[2]
我求出来是 -100,那如果我也是 dp[2] + array[3]
的话是 -93, 这时候 dp[2]
反而是累赘,最大就是自己(因为前面定义了必须以 i
为结尾,也就说必须以 7 结尾)。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] array = new int[n];
for(int i = 0; i < n; i++) {
array[i] = scanner.nextInt();
}
int sum = array[0];
int max = array[0];
for (int i = 1; i < n; i++) {
sum = Math.max(sum + array[i], array[i]);
if (sum >= max) {
max = sum;
}
}
System.out.println(max);
}
}
// 直接判断:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] array = new int[n];
int tmp = 0;
int max = Integer.MIN_VALUE;
for(int i = 0; i < n; i++) {
array[i] = scanner.nextInt();
tmp += array[i];
max = Math.max(max, tmp);
if(tmp < 0) { // 小于 0,前面的不需要,重新加
tmp = 0;
}
}
System.out.println(max);
}
}
// 如果是 递增 或 递减 连续子序列:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] array = new int[n + 1];
for(int i = 0; i < n; i++) {
array[i] = scanner.nextInt();
}
int tmp1 = 0;
int tmp2 = 0;
int max1 = 0;
int max2 = 0;
for(int i = 0; i < n; i++) {
if(array[i] >= array[i + 1]) {
tmp1 = array[i];
while (i < n && array[i] >= array[i + 1]) {
tmp1 += array[i + 1];
i++;
}
if(tmp1 > max1) {
max1 = tmp1;
}
}
if(i < n && array[i] <= array[i + 1]) {
tmp2 = array[i];
while (i < n && array[i] <= array[i + 1]) {
tmp2 += array[i + 1];
i++;
}
if(tmp2 > max2) {
max2 = tmp2;
}
}
i--;
}
System.out.println(Math.max(max1, max2));
}
}
“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。花花非常喜欢这种拥有对称美的回文串,生日的时候她得到两个礼物分别是字符串A和字符串B。现在她非常好奇有没有办法将字符串B插入字符串A使产生的字符串是一个回文串。你接受花花的请求,帮助她寻找有多少种插入办法可以使新串是一个回文串。如果字符串B插入的位置不同就考虑为不一样的办法。
例如:
A = “aba”,B = “b”。这里有4种把B插入A的办法:
* 在A的第一个字母之前: “baba” 不是回文
* 在第一个字母‘a’之后: “abba” 是回文
* 在字母‘b’之后: “abba” 是回文
* 在第二个字母’a’之后 “abab” 不是回文
所以满足条件的答案为2
输入描述:
每组输入数据共两行。
第一行为字符串A
第二行为字符串B
字符串长度均小于100且只包含小写字母
输出描述:
输出一个数字,表示把字符串B插入字符串A之后构成一个回文串的方法数示例1
输入
aba
b
输出
2
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String a = scanner.nextLine();
String b = scanner.nextLine();
int cnt = 0;
for (int i = 0; i <= a.length(); i++) {
StringBuilder sb = new StringBuilder(a);
sb.insert(i, b); // 直接插入
// sb.reverse 会将 sb 逆置,比较的就是逆置和逆置,用 tmp 逆置
StringBuilder tmp = new StringBuilder(sb);
StringBuilder str = tmp.reverse();
// 没有 equals 方法,转成字符串
if (sb.toString().equals(str.toString())) {
cnt++;
}
}
System.out.println(cnt);
}
import java.util.*;
public class Main {
public static boolean palindrome(String s) {
int left = 0;
int right = s.length() - 1;
while (left < right) {
if (s.charAt(left) != s.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String a = scanner.nextLine();
String b = scanner.nextLine();
int cnt = 0;
for (int i = 0; i <= a.length(); i++) { // 一个一个拼 测试回文
StringBuilder sb = new StringBuilder();
if(i == a.length()) {
// aa a
// i <= len,最后一次,b 拼在 a 最后
sb.append(a);
sb.append(b);
} else {
sb.append(a, 0, i);
sb.append(b);
sb.append(a, i, a.length());
}
if(palindrome(sb.toString())) { // 判断回文
cnt++;
}
}
System.out.println(cnt);
}
}
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。数值为 0 或者字符串不是一个合法的数值则返回 0。
数据范围:字符串长度满足 0 ≤ n ≤ 100
进阶:空间复杂度 O(1) ,时间复杂度 O(n)
注意:
①字符串中可能出现任意符号,出现除 +/- 以外符号时直接输出 0
②字符串中可能出现 +/- 且仅可能出现在字符串首位。
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
输入
"+2147483647"
输出
2147483647
public class Solution {
public int StrToInt(String str) {
if (str == null) {
return 0;
}
int ret = 0;
Boolean flg = false;
for (int i = 0; i < str.length(); i++) {
// 超出 int_max
if (ret > Integer.MAX_VALUE) {
return 0;
}
char ch = str.charAt(i);
if (i == 0 && (ch == '+' || ch == '-')) {
if (ch == '-') { // 负数
flg = true;
}
continue;
} else if (Character.isDigit(ch)) {
ret = ret * 10 + (ch - '0');
} else {
return 0;
}
}
return flg ? -ret : ret;
}
}
二货小易有一个W*H的网格盒子,网格的行编号为0 ~ H-1,网格的列编号为0 ~ W-1。每个格子至多可以放一块蛋糕,任意两块蛋糕的欧几里得距离不能等于2。
对于两个格子坐标(x1,y1),(x2,y2)的欧几里得距离为:
( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) 的算术平方根
小易想知道最多可以放多少块蛋糕在网格盒子里。
输入描述:
每组数组包含网格长宽W,H,用空格分割.(1 ≤ W、H ≤ 1000)
输出描述:
输出一个最多可以放的蛋糕数
输入
3 2
输出
4
【题目解析】:
本题看起来很难,实际是一个中等难度的题。本题如果没记错,是一个往年网易的笔试题,大家可以看到大厂的题的难度。
本题的重点是要读懂题意,并且需要多读两遍,才能读懂,本题本质就是在二维数组中每个坐标去放蛋糕,一
个坐标位置放了蛋糕,跟他欧几里得距离为2的位置不能放蛋糕,这个就是关键点。
对于两个格子坐标 (x1,y1),(x2,y2) 的欧几里得距离为: ( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) 的算术平方根 。
也就是说:如果(x1,y1)放了蛋糕,则满足 ( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) == 4 的 (x2,y2) 不能放蛋糕。
( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) == 4 看起来是一个无解的表达式,但是可以进行加法表达式分解:
1 + 3 = 4
3 + 1 = 4
2 + 2 = 4
0 + 4 = 4
4 + 0 = 4
仔细分析前三个表达式是不可能的,因为 (x1-x2) * (x1-x2) 表达式结果不能等于 2 或 3 。
a[i][j]
位置放蛋糕,则可以标记处 a[i][j+2] 和 a[i+1][j]
位置不能放蛋糕,这里要防止 [i+2]
和 [j+2]
越界,遍历一遍二维数组,标记处不能放蛋糕的位置,统计也就统计出了当蛋糕的位置数。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int w = scanner.nextInt();
int h = scanner.nextInt();
int count = 0;
int[][] array = new int[w][h];
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
if (array[i][j] == 0) {
count++;
if (i + 2 < w) {
array[i + 2][j] = 1;
}
if (j + 2 < h) {
array[i][j + 2] = 1;
}
}
}
}
System.out.println(count);
}
}
给定一个字符串A和其长度n,请返回一个bool值代表它是否为一个合法的括号串(只能由括号组成)。
测试样例:
"(()())",6
返回:true
测试样例:
"()a()()",7
返回:false
测试样例:
"()(()()",7
返回:false
import java.util.*;
public class Parenthesis {
public boolean chkParenthesis(String A, int n) {
// write code here
if (n % 2 != 0) {
return false;
}
Deque<Character> stack = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
char ch = A.charAt(i);
if (ch == '(') { // 左括号入栈
stack.offer(ch);
} else {
if (ch == ')' && !stack.isEmpty()) {
char val = stack.peek();
if (val == '(') { // 右括号 栈不为空 栈顶是左括号 出栈
stack.pop();
}
} else {
return false;
}
}
}
return stack.isEmpty();
}
}
考拉有n个字符串字符串,任意两个字符串长度都是不同的。考拉最近学习到有两种字符串的排序方法: 1.根据字符串的字典序排序。例如:
“car” < “carriage” < “cats” < "doggies < “koala”
2.根据字符串的长度排序。例如:
“car” < “cats” < “koala” < “doggies” < “carriage”
考拉想知道自己的这些字符串排列顺序是否满足这两种排序方法,考拉要忙着吃树叶,所以需要你来帮忙验证。
输入描述:
输入第一行为字符串个数n(n ≤ 100)
接下来的n行,每行一个字符串,字符串长度均小于100,均由小写字母组成
输出描述:
如果这些字符串是根据字典序排列而不是根据长度排列输出"lexicographically",
如果根据长度排列而不是字典序排列输出"lengths",
如果两种方式都符合输出"both",否则输出"none"
输入
3
a
aa
bbb
输出
both
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
String[] array = new String[n];
Boolean len = true;
Boolean letter = true;
for (int i = 0; i < n; i++) {
array[i] = scanner.next(); // next
if (i != 0 && len && array[i - 1].length() > array[i].length()) {
len = false;
}
if (i != 0 && letter && array[i - 1].compareTo(array[i]) > 0) {
letter = false;
}
}
if (len && letter) {
System.out.println("both");
} else if (len) {
System.out.println("lengths");
} else if (letter) {
System.out.println("lexicographically");
} else {
System.out.println("none");
}
}
}
public static void main(String[] args) throws IOException {
// BufferedReader 从字符流中读取文本并且缓存
BufferedReader bi = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(bi.readLine());
}
// 只有长度递增 和 字典排序从小到大
public class Main {
public static void main5(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
String[] array = new String[n];
Boolean len1 = true;
Boolean len2 = true;
Boolean letter1 = true;
Boolean letter2 = true;
for (int i = 0; i < n; i++) {
array[i] = scanner.next();
if (i != 0 && len1 && array[i - 1].length() < array[i].length()) {
len2 = false; // 不是递增
}
if (i != 0 && len2 && array[i - 1].length() > array[i].length()) {
len1 = false; // 不是递减
}
if (i != 0 && letter2 && array[i - 1].compareTo(array[i]) < 0) {
letter2 = false;
}
if (i != 0 && letter1 && array[i - 1].compareTo(array[i]) > 0) {
letter1 = false;
}
}
Boolean len = len1 || len2;
Boolean letter = letter1 || letter2;
if (len && letter) {
System.out.println("both");
} else if (len) {
System.out.println("lengths");
} else if (letter) {
System.out.println("lexicographically");
} else {
System.out.println("none");
}
}
}
链接:
正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。
输入描述:
输入两个正整数A和B。
输出描述:
输出A和B的最小公倍数。示例1
输入
5 7
输出
35
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int b = scanner.nextInt();
int m = a;
int n = b;
int c = 0;
while ((c = a % b) != 0) {
a = b;
b = c;
}
System.out.println(m *n / b);
}
public static void main1(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int b = scanner.nextInt();
int c = Math.max(a, b);
while (true) {
if (c % a == 0 && c % b == 0) {
System.out.println(c);
break;
}
c++;
}
}
}
链接:
给定两个int A和B。编写一个函数返回A+B的值,但不得使用+或其他算数运算符。
测试样例:
1,2
返回:3
【题目解析】:
1、二进制位想异或的结果,是两个数对应为相加的结果,不考虑进位
1 ^ 2
0001 ^ 0010 = 0011 = 3
2、二进制位与向左移一位的结果,是两个数相加进位后的结果,(只考虑进位)
1 & 2 << 1
(0001 & 0010) << 1 = 0000
结论:两个数相加,如果不需要进位,这两个数异或的值就是这两个数的和
例:2 + 3
A = 0010
B = 0011
第一次:
sum = A ^ B = 0010 ^ 0011 = 0001
carry = (A & B) << 1 = (0010 << 1) = 0100
A = sum = 0001
B = carry = 0100
第二次:
sum = A ^ B = 0001 ^ 0100 = 0101 此次 sum 就是 A + B 的和
carry = (A & B) << 1 = (0000) << 1 = 0000
A = sum = 0101
B = carry = 0000
import java.util.*;
public class UnusualAdd {
public int addAB(int A, int B) {
// write code here
if (B == 0) {
return A;
}
int sum = 0;
int carry = 0;
while (B != 0) {
sum = A ^ B;
carry = (A & B) << 1;
A = sum;
B = carry;
}
return A;
}
}
请计算n*m的棋盘格子(n为横向的格子数,m为竖向的格子数)从棋盘左上角出发沿着边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即:只能往右和往下走,不能往左和往上走。
注:沿棋盘格之间的边缘线行走
数据范围: 1≤n,m≤8 1 \le n,m \le 8 \ 1≤n,m≤8
输入描述:
输入两个正整数n和m,用空格隔开。(1≤n,m≤8)
输出描述:
输出一行结果
输入
2 2
输出
6
【题目解析】:
import java.util.*;
public class Main {
public static int route(int n, int m) {
// n == 1 或 m == 1
if ((n == 1 && m >= 1) || (n >= 1 && m == 1)) {
return n + m;
}
// n > 1 && m > 1
return route(n - 1, m) + route(n, m -1);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int routes = route(n, m);
System.out.println(routes);
}
}
给定一个二维数组board,代表棋盘,其中元素为1的代表是当前玩家的棋子,0表示没有棋子,-1代表是对方玩家的棋子。当一方棋子在横竖斜方向上有连成排的及获胜(及井字棋规则),返回当前玩家是否胜出。
测试样例:
[[1,0,1],[1,-1,-1],[1,-1,0]]
返回:true
解法一:判断
import java.util.*;
public class Board {
public boolean checkWon(int[][] board) {
// write code here
Boolean row = true; // 行
for (int i = 0; i < board.length; i++) {
row = true;
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] != 1) {
row = false;
break;
}
}
}
if (row) return true; // 列
Boolean col = true;
for (int i = 0; i < board.length; i++) {
row = true;
for (int j = 0; j < board[0].length; j++) {
if (board[j][i] != 1) {
col = false;
break;
}
}
}
if (col) return true;
Boolean slash1 = true; // 左对角线
Boolean slash2 = true; // 右对角线
int j1 = 0;
int j2 = board.length - 1;
for (int i = 0; i < board.length; i++) {
if (slash1 && board[i][j1++] != 1) {
slash1 = false;
}
if (slash2 && board[j2][i] != 1) {
slash2 = false;
}
}
if (slash1 || slash2) return true;
return false;
}
}
解法二:计算
判断行,如果某一行元素和为 3,玩家胜出,返回 true
判断列,如果某一列元素和为 3,玩家胜出,返回 true
判断主副对角线,如果主副对角线元素和为 3,玩家胜出,返回 true
import java.util.*;
public class Board {
public boolean checkWon(int[][] board) {
int n = board.length;
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = 0; j < n; j++) {
sum += board[i][j]; // 行
}
if (sum == 3) {
return true;
}
}
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = 0; j < n; j++) {
sum += board[j][i]; // 列
}
if (sum == 3) {
return true;
}
}
int sum1 = 0;
int sum2 = 0;
for (int i = 0; i < n; i++) {
sum1 += board[i][i]; // 左对角线
sum2 += board[n - 1 - i][i]; // 右对角线
}
if (sum1 == 3 || sum2 == 3) {
return true;
}
return false;
}
}
密码按如下规则进行计分,并根据不同的得分为密码进行安全等级划分。
一、密码长度:
5 分: 小于等于4 个字符
10 分: 5 到7 字符
25 分: 大于等于8 个字符
二、字母:
0 分: 没有字母
10 分: 密码里的字母全都是小(大)写字母
20 分: 密码里的字母符合”大小写混合“
三、数字:
0 分: 没有数字
10 分: 1 个数字
20 分: 大于1 个数字
四、符号:
0 分: 没有符号
10 分: 1 个符号
25 分: 大于1 个符号
五、奖励(只能选符合最多的那一种奖励):
2 分: 字母和数字
3 分: 字母、数字和符
5 分: 大小写字母、数字和符号
最后的评分标准:
>= 90: 非常安全
>= 80: 安全(Secure)
>= 70: 非常强
>= 60: 强(Strong)
>= 50: 一般(Average)
>= 25: 弱(Weak)
>= 0: 非常弱(Very_Weak)
对应输出为:
VERY_SECURE
SECURE
VERY_STRONG
STRONG
AVERAGE
WEAK
VERY_WEAK
请根据输入的密码字符串,进行安全评定。
注:
字母:a-z, A-Z
数字:0-9
符号包含如下: (ASCII码表可以在UltraEdit的菜单view->ASCII Table查看)
!"#$%&'()*+,-./ (ASCII码:0x21~0x2F)
:;<=>?@ (ASCII码:0x3A~0x40)
[]^_` (ASCII码:0x5B~0x60)
{|}~ (ASCII码:0x7B~0x7E)
提示:
1 <= 字符串的长度<= 300
输入描述:
输入一个string的密码
输出描述:
输出密码等级
输入
38$@NoNoN
输出
VERY_SECURE
说明
样例的密码长度大于等于8个字符,得25分;大小写字母都有所以得20分;有两个数字,所以得20分;包含大于1符号,所以得25分;由于该密码包含大小写字母、数字和符号,所以奖励部分得5分,经统计得该密码的密码强度为25+20+20+25+5=95分。
import java.util.*;
public class Main {
public static int passwordLevel(String s) {
int score = 0;
// 长度
int len = s.length();
if (len <= 4) {
score += 5;
} else if (len >= 5 && len <= 7) {
score += 10;
} else {
score += 25;
}
// 统计字符个数
int Upletter = 0; // 大写字母
int Loletter = 0; // 小写字母
int digit = 0; // 数字
int symbol = 0; // 符号
for (int i= 0; i < len; i++) {
char ch = s.charAt(i);
if (Character.isLowerCase(ch)) {
Loletter++;
} else if (Character.isUpperCase(ch)) {
Upletter++;
} else if (ch >= '0' && ch <= '9') {
digit++;
} else {
symbol++;
}
}
// 加分
if ((Upletter + Loletter) > 0) { // 有字母
if (Upletter == 0 || Loletter == 0) { // 都是大写或小写
score += 10;
} else {
score += 20; // 大小写混合
}
}
if (digit == 1) { // 一个数字
score += 10;
} else if (digit > 1) { // 超过一个数字
score += 20;
}
if (symbol == 1) { // 一个符号
score += 10;
} else if (symbol > 1) { // 超过一个符号
score += 25;
}
// 奖励
if (Upletter != 0 && Loletter != 0 && digit != 0 && symbol != 0) {
score += 5;
} else if ((Upletter + Loletter) != 0 && digit != 0 && symbol != 0) {
score += 3;
} else if ((Upletter + Loletter) != 0 && digit != 0) {
score += 2;
}
return score;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
int score = passwordLevel(str);
if (score >= 90) {
System.out.println("VERY_SECURE");
} else if (score >= 80) {
System.out.println("SECURE");
} else if (score >= 70) {
System.out.println("VERY_STRONG");
} else if (score >= 60) {
System.out.println("STRONG");
} else if (score >= 50) {
System.out.println("AVERAGE");
} else if (score >= 25) {
System.out.println("WEAK");
} else {
System.out.println("VERY_WEAK");
}
}
}
求一个int类型数字对应的二进制数字中1的最大连续数,例如3的二进制为00000011,最大连续2个1
数据范围:数据组数:1≤t≤5 1\le t\le 5\ 1≤t≤5 ,1≤n≤500000 1\le n\le 500000\ 1≤n≤500000
进阶:时间复杂度:O(logn) ,空间复杂度:O(1)
输入描述:
输入一个int类型数字
输出描述:
输出转成二进制之后连续1的个数
输入
200
输出
2
说明
200的二进制表示是11001000,最多有2个连续的1。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int max = 0;
int cnt = 0;
while (n != 0) {
if ((n & 1) == 1) {
cnt++;
max = Math.max(max, cnt);
} else {
cnt = 0;
}
n >>= 1;
}
/* while (n != 0) {
cnt = 0;
if (n != 0 && n % 2 == 1) {
while (n != 0 && n % 2 == 1) {
cnt++;
n /= 2;
}
} else {
n /= 2;
}
if (cnt > max) {
max = cnt;
}
} */
System.out.println(max);
}
}
将一棵无穷大满二叉树的结点按根结点一层一层地从左往右编号,根结点编号为1。现给定a,b为两个结点。设计一个算法,返回a、b最近的公共祖先的编号。注意其祖先也可能是结点本身。
测试样例:
2,3
返回:1
import java.util.*;
public class LCA {
public int getLCA(int a, int b) {
// write code here
if (a == b) {
return a;
}
while (a != b) {
// parent = child / 2;
if (a > b) {
a /= 2;
} else {
b /= 2;
}
}
return a;
}
}
给定两个 32 位整数 n 和 m,同时给定 i 和 j ,将 m 的二进制数位插入到 n 的二进制的第 j 到第 i 位,保证 n 的第 j 到第 i 位均为零,且m的二进制位数小于等于 i - j + 1 ,其中二进制的位数从 0 开始由低到高。
测试样例:
1024,19,2,6
返回:1100
import java.util.*;
public class BinInsert {
public static int binInsert(int n, int m, int j, int i) {
m <<= j;
return n | m;
}
public static int binInsert1(int n, int m, int j, int i) {
// write code here
int[] array1 = new int[32]; // n
int k = 31;
while (n != 0) {
array1[k--] = n % 2;
n /= 2;
}
int[] array2 = new int[32]; // m
k = 31;
while (m != 0) {
array2[k--] = m % 2;
m /= 2;
}
// m 二进制序列从31开始,插入 n 的二进制 j -- i
// 1024 -- 100 0000 0000
// 19 -- 100 11
// 替换 -- 100 0100 1100 -- 1100
int tmp = 31;
for (k = 32 - j - 1; k >= 32 - i - 1; k--) { // 29 - 25
array1[k] = array2[tmp];
tmp--;
}
// 跳过高位的 0
Boolean flg = true;
StringBuilder sb = new StringBuilder();
for (k = 0; k < 32; k++) {
if (k == 0 && flg && array1[k] == 0) { // 跳过高位的 0
flg = false;
while (k < 32 && array1[k] == 0) {
k++;
}
}
if (k < 32) {
sb.append(array1[k]);
}
}
// 转数字
int ret = 0;
for (k = 0; k < sb.length(); k++) {
ret = ret * 2 + sb.charAt(k) - '0';
}
return ret;
}
}
任意一个偶数(大于2)都可以由2个素数组成,组成偶数的2个素数有很多种情况,本题目要求输出组成指定偶数的两个素数差值最小的素数对。
数据范围:输入的数据满足 4 ≤ n ≤ 1000
输入描述:
输入一个大于 2 的偶数
输出描述:
从小到大输出两个素数
输入
20
import java.util.*;
public class Main {
public static Boolean isPrime(int n) {
int i = 2;
for (; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
/* if (i > Math.sqrt(n)) {
return true;
}
return false; */
return true;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int min = n;
int[] array= new int[2];
// 包括一半 4 --> 2 2 118 --> 59 59
for (int i = 2; i <= n / 2; i++) {
if (isPrime(i) && isPrime(n - i)) { // i 和 n - 1 是素数
if (n - i - i < min) {
min = n - i - i;
array[0] = i;
array[1] = n - i;
}
}
}
System.out.println(array[0] + "\n" + array[1]);
}
}
在命令行输入如下命令:
xcopy /s c:\ d:\e,
各个参数如下:
参数1:命令字xcopy
参数2:字符串/s
参数3:字符串c:\
参数4: 字符串d:\e
请编写一个参数解析程序,实现将命令行各个参数解析出来。
解析规则:
1.参数分隔符为空格
2.对于用""包含起来的参数,如果中间有空格,不能解析为多个参数。比如在命令行输入xcopy /s “C:\program files” "d:“时,参数仍然是4个,第3个参数应该是字符串C:\program files,而不是C:\program,注意输出参数时,需要将”"去掉,引号不存在嵌套情况。
3.参数不定长
4.输入由用例保证,不会出现不符合要求的输入
数据范围:字符串长度:1≤s≤1000
进阶:时间复杂度:O(n),空间复杂度:O(n)
输入描述:
输入一行字符串,可以有空格
输出描述:
输出参数个数,分解后的参数,每个参数都独占一行
输入
xcopy /s c:\\ d:\\e
输出
4
xcopy
/s
c:\\
d:\\e
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
int count = 0;
List<String> list = new ArrayList<>();
// 解析 保存入 list
for (int i = 0; i < str.length(); i++) {
StringBuilder stringBuilder = new StringBuilder(); // 每个参数
// 1、双引号引起的一个参数
if (str.charAt(i) == '"') {
i++; // 双引号需要去掉
while (i < str.length() && str.charAt(i) != '"') {
stringBuilder.append(str.charAt(i));
i++;
}
} else {
// 2、普通参数
while (i < str.length() && str.charAt(i) != ' ') {
stringBuilder.append(str.charAt(i));
i++;
}
}
// 防止空格,此次没有满足条件进入 if 获取参数,也加入了空串,count 多一个
// 比较 len 不能与 null 比较
if (stringBuilder.length() != 0) {
list.add(stringBuilder.toString()); // 加入 list
count++; // 参数加一
}
}
// 打印 个数 和 每个参数
System.out.println(count);
for (String s : list) {
System.out.println(s);
}
}
public static void main1(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
int count = 0;
List<String> list = new ArrayList<>();
for (int i = 0; i < str.length(); i++) {
String s = ""; // string 初识化为 空串
if (str.charAt(i) == '"') {
while (i < str.length() && str.charAt(i) != '"') {
s += str.charAt(i);
i++;
}
} else {
while (i < str.length() && str.charAt(i) != ' ') {
s += str.charAt(i);
i++;
}
}
if (s != "") { // 比较是否为空串
list.add(s);
count++;
}
}
System.out.println(count);
for (String s : list) {
System.out.println(s);
}
}
}
写法二:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
int count = 0;
for (int i = 0; i < str.length(); i++) {
// 双引号引起的参数
if (str.charAt(i) == '"') {
do {
i++;
} while (str.charAt(i) != '"');
}
// 碰到双引号以外的空格 count++
if (str.charAt(i) == ' ') {
count++;
}
}
System.out.println(count + 1); // 参数比空格多一个
int flag = 1;
for (int i = 0; i < str.length(); i++) {
// 碰到第一个 "",flag 变 0,碰到第二个 "",flag 变 1
// flag == 0 时,一直在遍历双引号中的参数
if (str.charAt(i) == '"') {
flag ^= 1;
}
// 除了 "" 和 双引号中的空格,其他都输出
if (str.charAt(i) != ' ' && str.charAt(i) != '"') {
System.out.print(str.charAt(i));
}
// 双引号中的空格,输出
if (str.charAt(i) == ' ' && flag == 0) {
System.out.print(str.charAt(i));
}
// 双引号中以外的空格,换行
if (str.charAt(i) == ' ' && flag == 1) {
System.out.println();
}
}
}
}
小易来到了一条石板路前,每块石板上从1挨着编号为:1、2、3…
这条石板路要根据特殊的规则才能前进:对于小易当前所在的编号为K的 石板,小易单次只能往前跳K的一个约数(不含1和K)步,即跳到K+X(X为K的一个非1和本身的约数)的位置。 小易当前处在编号为N的石板,他想跳到编号恰好为M的石板去,小易想知道最少需要跳跃几次可以到达。
例如:
N = 4,M = 24:
4->6->8->12->18->24
于是小易最少需要跳跃5次,就可以从4号石板跳到24号石板
输入描述:
输入为一行,有两个整数N,M,以空格隔开。 (4 ≤ N ≤ 100000) (N ≤ M ≤ 100000)
输出描述:
输出小易最少需要跳跃的步数,如果不能到达输出-1
输入
4 24
输出
5
解法:动态规划
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[] step = new int[m + 1]; // 和石板对应
// 初始化
for (int i = 0; i < m + 1; i++) { // m + 1
step[i] = Integer.MAX_VALUE;
}
step[n] = 0;
for (int i = n; i < m; i++) {
if (step[i] == Integer.MAX_VALUE) {
continue;
}
// 求当前石板的约数
List<Integer> list = div(i);
// j -> 当前石板一次可以跳几块石板
// i -> 当前石板的编号
for (int j : list) {
if (i + j <= m) { // <=
if (step[i + j] != Integer.MAX_VALUE) {
// 之间跳的步数 与 此处跳的步数 最小值
step[i + j] = Math.min(step[i + j], step[i] + 1);
} else {
// 没有跳过此石板
step[i + j] = step[i] + 1;
}
}
}
}
if (step[m] == Integer.MAX_VALUE) { // 不能到达
System.out.println(-1);
} else {
System.out.println(step[m]);
}
}
public static List<Integer> div(int num) {
List<Integer> list = new ArrayList<>();
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) {
list.add(i);
if (num / i != i) { // 两约数不同
list.add(num / i);
}
}
}
return list;
}
}
根据输入的日期,计算是这一年的第几天。
保证年份为4位数且日期合法。
进阶:时间复杂度:O(n) O(n)\ O(n) ,空间复杂度:O(1) O(1)\ O(1)
输入描述:
输入一行,每行空格分割,分别是年,月,日
输出描述:
输出是这一年的第几天
输入
2012 12 31
输出
366
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int year = scanner.nextInt();
int month = scanner.nextInt();
int day = scanner.nextInt();
int[] amount = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //
// 闰年 2月变29天
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
amount[1]++;
}
int ans = 0;
for (int i = 0; i < month - 1; i++) {
ans += amount[i];
}
System.out.println(ans + day);
}
}
一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。
输入描述:
第一行输入一个正整数n(n ≤ 1000)
第二行为n个数正整数xi(xi ≤ 1000)
输出描述:
输出可以产生的幸运的袋子数
输入
3
1 1 1
输出
2
【题目解析】:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = scanner.nextInt();
}
// 排序
Arrays.sort(array);
// 数组 长度 起始位置 和 积
int nums = numOfLuckyBags(array, n, 0, 0, 1);
System.out.println(nums);
}
private static int numOfLuckyBags(int[] array, int n, int pos, int sum, int multi) {
int count = 0;
for (int i = pos; i < n; i++) {
sum += array[i];
multi *= array[i];
if (sum > multi) {
count += 1 + numOfLuckyBags(array, n, i + 1, sum, multi);
} else if (array[i] == 1) {
// 初始情况 等于 1 ,不满足 sum > multi,往下判断
count += numOfLuckyBags(array, n, i + 1, sum, multi);
} else {
// 递归结束
break;
}
// 回溯
sum -= array[i];
multi /= array[i];
// 相同的号码无区别 跳过
while (i < n - 1 && array[i] == array[i + 1]) {
i++;
}
}
return count;
}
}
输入一个正整数,计算它在二进制下的1的个数。
注意多组输入输出!!!!!!
数据范围: 1≤n≤231−1 1 \le n \le 2^{31}-1 \ 1≤n≤231−1
输入描述:
输入一个整数
输出描述:
计算整数二进制中1的个数
输入
5
输出
2
说明
5的二进制表示是101,有2个1
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextInt()) {
int n = scanner.nextInt();
int count = 0;
while (n != 0) {
n = n & (n - 1);
count++;
}
System.out.println(count);
}
}
}
在地下室里放着n种颜色的手套,手套分左右手,但是每种颜色的左右手手套个数不一定相同。A先生现在要出门,所以他要去地下室选手套。但是昏暗的灯光让他无法分辨手套的颜色,只能分辨出左右手。所以他会多拿一些手套,然后选出一双颜色相同的左右手手套。现在的问题是,他至少要拿多少只手套(左手加右手),才能保证一定能选出一双颜色相同的手套。
给定颜色种数n(1≤n≤13),同时给定两个长度为n的数组left,right,分别代表每种颜色左右手手套的数量。数据保证左右的手套总数均不超过26,且一定存在至少一种合法方案。
测试样例:
4,[0,7,1,6],[1,5,0,6]
返回:10(解释:可以左手手套取2只,右手手套取8只)
【题目解析】:
左手或右手每一种颜色的手套都可以取到:总数 - 最小值 + 1
公式:min(leftSum - leftMin + 1, rightSum - rightMin + 1) + 1(求得左右手,取较小值,加另一只手的任何一只手套,即为答案)
特殊情况:1、最小值是除之外 0 的最小值,
2、数量为 0 时,要加上另一只手的对应颜色手套
import java.util.*;
public class Gloves {
public int findMinimum(int n, int[] left, int[] right) {
// write code here
int leftSum = 0;
int rightSum = 0;
int leftMin = Integer.MAX_VALUE;
int rightMin = Integer.MAX_VALUE;
int zero = 0;
for (int i = 0; i < n; i++) {
if (left[i] * right[i] == 0) {
zero += left[i] + right[i];
} else {
leftSum += left[i];
rightSum += right[i];
leftMin = Math.min(leftMin, left[i]);
rightMin = Math.min(rightMin, right[i]);
}
}
return Math.min(leftSum - leftMin + 1, rightSum - rightMin + 1) + 1 + zero;
}
}
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。
它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。
输入n,请输出n以内(含n)完全数的个数。
数据范围: 1≤n≤5×105
输入描述:
输入一个数字n
输出描述:
输出不超过n的完全数的个数
输入
1000
输出
3
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int count = 0;
for (int i = 1; i <= n; i++) {
if (perfectNum(i)) {
count++;
}
}
System.out.println(count);
}
public static Boolean perfectNum(int n) {
int sum = 0;
for (int i = 1; i < n; i++) {
if (n % i == 0) {
sum += i;
}
}
return n == sum;
}
}
扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A,2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王)
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用“-”连接,每手牌的每张牌以空格分隔,“-”两边没有空格,如:4 4 4 4-joker JOKER
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR
基本规则:
(1)输入每手牌可能是个子,对子,顺子(连续5张),三个,炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子)
(3)大小规则跟大家平时了解的常见规则相同,个子,对子,三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;
(4)输入的两手牌不会出现相等的情况。
答案提示:
(1)除了炸弹和对王之外,其他必须同类型比较。
(2)输入已经保证合法性,不用检查输入是否是合法的牌。
(3)输入的顺子已经经过从小到大排序,因此不用再排序了.
数据范围:保证输入合法
输入描述:
输入两手牌,两手牌之间用“-”连接,每手牌的每张牌以空格分隔,“-”两边没有空格,如4 4 4 4-joker JOKER。
输出描述:
输出两手牌中较大的那手,不含连接符,扑克牌顺序不变,仍以空格隔开;如果不存在比较关系则输出ERROR。
输入
4 4 4 4-joker JOKER
输出
joker JOKER
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
String[] pp = str.split("-"); // 两手牌
String[] p1 = pp[0].split(" "); // 每张牌分开
String[] p2 = pp[1].split(" ");
String cmp = "34567891JQKA2"; // 用 1 代替 10
if (pp[0].equals("joker JOKER") || pp[1].equals("joker JOKER")) { // 1、对王最大
System.out.println("joker JOKER");
} else if (p1.length == p2.length) { // 2、两手牌长度一样,比较牌面
if (cmp.indexOf(p1[0].substring(0, 1)) > cmp.indexOf(p2[0].substring(0, 1))) {
// 比较第一张牌在 cmp 中的位置,如果是 10,需要再分开,找 1。
System.out.println(pp[0]);
} else {
System.out.println(pp[1]);
}
} else if (p1.length == 4) { // 3、判断是不是炸弹
System.out.println(pp[0]);
} else if (p2.length == 4) {
System.out.println(pp[1]);
} else { // 4、不存在比较关系
System.out.println("ERROR");
}
}
}
操作给定的二叉树,将其变换为源二叉树的镜像。
数据范围:二叉树的节点数 0≤n≤10000 , 二叉树每个节点的值 0≤val≤10000
要求: 空间复杂度 O(n)。本题也有原地操作,即空间复杂度 O(1)的解法,时间复杂度 O(n)
示例1
输入
{8,6,10,5,7,9,11}
输出
{8,10,6,11,9,7,5}
public class Solution {
public TreeNode Mirror (TreeNode pRoot) {
// write code here
if (pRoot == null) {
return pRoot;
}
// 只有根节点,返回根节点
if (pRoot.left == null && pRoot.right == null) { // &&
return pRoot;
}
// 每次根节点不变 交换左右节点
TreeNode tmp = pRoot.left;
pRoot.left = pRoot.right;
pRoot.right = tmp;
// 遍历左右子树
if (pRoot.left != null) {
Mirror(pRoot.left);
}
if (pRoot.right != null) {
Mirror(pRoot.right);
}
return pRoot;
}
}
line1:1
line2:1 1 1
line3:1 2 2 1
line4:1 3 4 3 1
line5:1 4 7 7 4 1
line6:1 5 11 14 11 5 1
line7:1 6 16 25 25 16 6 1
line8:1 7 22 41 50 41 22 7 1
line9:1 8 29 63 91 91 63 29 8 1
line10: 1 9 37 92 154 182 154 92 37 9 1
以上三角形的数阵,第一行只有一个数1,以下每行的每个数,是恰好是它上面的数、左上角数和右上角的数,3个数之和(如果不存在某个数,认为该数就是0)。
求第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3,输入2则输出-1。
数据范围: 1≤n≤109
输入描述:
输入一个int整数
输出描述:
输出返回的int值
示例1
输入
4
输出
3
【解题思路】:
寻找规律,运行通过:-1 -1 (2 3 2 4)···(2 3 2 4)
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] ret = new int[]{2, 3, 2, 4};
while (scanner.hasNextInt()) {
int n = scanner.nextInt();
if (n <= 2) {
System.out.println(-1);
} else {
System.out.println(ret[(n + 1) % 4]);
}
}
}
}
按照题目意思,可以发现第n行有2n - 1个元素,第i,j元素等于上一行第j - 2,j - 1,j三列元素之和,每一行的第
一列和最后一列都为1,如果是第二列,则只是两个元素之和
import java.util.*;
public class Main {
// 执行出错...
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = 2 * n - 1; // 第 n 行,有 2n-1 个数
int[][] a = new int[n][m];
// 初始化
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
a[i][j] = 0;
}
}
// 计算到 第 n 行
a[0][0] = 1; // 第一行
for (int i = 1; i < n; i++) {
a[i][0] = a[i][2 * i] = 1; // 首尾
// for (int j = 1; j <= 2 * i - 1; j++) {
for (int j = 1; j <= 2 * i - 1; j++) {
if (j == 1) { // j == 1 -> 只有两个 会越界
a[i][j] = a[i - 1][j] + a[i - 1][j - 1];
} else { // j == 2n-1 -> 加上 0 也没关系
a[i][j] = a[i - 1][j] + a[i - 1][j - 1] + a[i - 1][j - 2];
}
}
}
for (int k = 0; k < m; k++) {
if (a[n - 1][k] % 2 == 0) { // 第 n 行,判断
System.out.println(k + 1); // 第几个 加 1
return;
}
}
System.out.println(-1);
}
// 运行超时
public static void main1(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
List<List<Integer>> list = new ArrayList<>();
List<Integer> ret = new ArrayList<>(); // 第一行
ret.add(1);
list.add(ret);
for (int i = 1; i < n; i++) { // n 行
List<Integer> tmp = new ArrayList<>();
tmp.add(1); // 首
List<Integer> preRow = list.get(i - 1); // 上一行
for (int j = 1; j <= 2 * i - 1; j++) { // 2n - 1 个
// 左上角上数的和
int num = 0;
if (j - 2 >= 0 && j - 2 < preRow.size()) {
num += preRow.get(j - 2);
}
if (j - 1 >= 0 && j - 1 < preRow.size()) {
num += preRow.get(j - 1);
}
if (j >= 0 && j < preRow.size()) {
num += preRow.get(j);
}
tmp.add(num);
}
tmp.add(1); // 尾
list.add(tmp);
}
List<Integer> ans = list.get(n - 1); // 第 n 行
int i = 0;
for (; i < ans.size(); i++) {
if (ans.get(i) % 2 == 0) {
System.out.println(i + 1); // 第几个,从 1 开始数,加 1
break;
}
}
if (i == ans.size()) {
System.out.println(-1); // 没有偶数
}
}
}
统计每个月兔子的总数
有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。
例子:假设一只兔子第3个月出生,那么它第5个月开始会每个月生一只兔子。
一月的时候有一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?
数据范围:输入满足 1≤n≤31
输入描述:
输入一个int型整数表示第n个月
输出描述:
输出对应的兔子总数
输入
3
输出
2
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int count = getRabbitCnt(n);
System.out.println(count);
}
private static int getRabbitCnt(int n) {
if (n < 3) {
return 1;
}
return getRabbitCnt(n - 1) + getRabbitCnt(n - 2);
}
}
问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。
要求:
实现如下2个通配符:
:匹配0个或以上的字符(注:能被和?匹配的字符仅由英文字母和数字0到9组成,下同)
?:匹配1个字符
注意:匹配时不区分大小写。
输入:
通配符表达式;
一组字符串。
输出:
返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false
数据范围:字符串长度:1≤s≤100
进阶:时间复杂度:O(n2) ,空间复杂度:O(n)
输入描述:
先输入一个带有通配符的字符串,再输入一个需要匹配的字符串
输出描述:
返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false
示例1
输入
te?t*.*
txt12.xls
输出
false
【解题思路】:
j | * | B | C | * | ? | |
---|---|---|---|---|---|---|
i | T | T | F | F | F | F |
a | F | T | F | F | F | F |
b | F | T | T | F | F | F |
c | F | T | F | T | T | F |
d | F | T | F | F | T | T |
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String t = scanner.nextLine(); // 通配符字符串
String s = scanner.nextLine(); // 待匹配字符串
System.out.println(isMatch(s, t));
}
private static boolean isMatch(String s, String t) {
int lt = t.length();
int ls = s.length();
boolean[][] dp = new boolean[ls + 1][lt + 1];
dp[0][0] = true;
for (int i = 0; i <= ls; i++) {
for (int j = 1; j <= lt; j++) {
if (i == 0) { // 1、第一行
if (t.charAt(j - 1) == '*') { //
dp[i][j] = dp[i][j - 1];
}
continue;
}
char cs = s.charAt(i - 1);
char ct = t.charAt(j - 1);
if (ct == '*') { // 2、*
if (cs == '.' || (cs >= 'A' && cs <= 'z') || (cs >= '0' && cs <= '9')) { // 只能匹配字母 数字 点
dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; // 前面 或 上面
}
} else if (ct == '?') { // 3、?
if (cs == '.' ||(cs >= 'A' && cs <= 'z') || (cs >= '0' && cs <= '9')) { // 只能匹配字母 数字 点
dp[i][j] = dp[i - 1][j - 1]; // 看上一个
}
} else if (Character.toLowerCase(cs) == Character.toLowerCase(ct)) { // 4、不区分大小写匹配
dp[i][j] = dp[i - 1][j - 1]; // 看上一个
}
}
}
return dp[ls][lt];
}
}
class Solution {
public boolean isMatch(String s, String p) {
// dp[i][j] 表示 s 的前 i 个字符和 p 的前 j 个字符是否匹配
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];
// 初始化
dp[0][0] = true;
for (int j = 1; j <= n; j++) {
// 第一列 是空 不匹配 默认是 false 不用管
// 第一列 如果是 * 就看前一个
dp[0][j] = p.charAt(j - 1) == '*' && dp[0][j - 1];
}
// 状态转移
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?') {
dp[i][j] = dp[i - 1][j - 1]; // 看上一个
} else if (p.charAt(j - 1) == '*') {
dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; // 前面 或 上面
}
}
}
return dp[m][n];
}
}
某商店规定:三个空汽水瓶可以换一瓶汽水,允许向老板借空汽水瓶(但是必须要归还)。
小张手上有n个空汽水瓶,她想知道自己最多可以喝到多少瓶汽水。
数据范围:输入的正整数满足 1≤n≤100
注意:本题存在多组输入。输入的 0 表示输入结束,并不用输出结果。
输入描述:
输入文件最多包含 10 组测试数据,每个数据占一行,仅包含一个正整数 n( 1<=n<=100 ),表示小张手上的空汽水瓶数。n=0 表示输入结束,你的程序不应当处理这一行。
输出描述:
对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。
输入
3
10
81
0
输出
1
5
40
说明
样例 1 解释:用三个空瓶换一瓶汽水,剩一个空瓶无法继续交换
样例 2 解释:用九个空瓶换三瓶汽水,剩四个空瓶再用三个空瓶换一瓶汽水,剩两个空瓶,向老板借一个空瓶再用三个空瓶换一瓶汽水喝完得一个空瓶还给老板
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextInt()) {
int bottle = scanner.nextInt();
int cnt = 0;
if (bottle != 0) {
while (bottle >= 2) {
cnt += bottle / 3;
bottle = bottle / 3 + bottle % 3;
if (bottle == 2) {
cnt += 1;
bottle = 0;
}
}
System.out.println(cnt);
}
}
}
}
查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!
数据范围:字符串长度1≤length≤300
进阶:时间复杂度:O(n3) ,空间复杂度:O(n)
输入描述:
输入两个字符串
输出描述:
返回重复出现的字符
输入
abcdefghijklmnop
abcsafjklmnopqrstuvw
输出
jklmnop
【解题思路:】
1、暴力解法:判断 i - j 子串存在,比较长度,更新
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s1 = scanner.nextLine();
String s2 = scanner.nextLine();
String str = s1.length() >= s2.length() ? s1 : s2;
String sub = s1.length() < s2.length() ? s1 : s2; // 不加等号 两个长度相等 会变成同一个
int max = 0;
String ans = "";
for (int i = 0; i < sub.length(); i++) {
for (int j = i; j <= sub.length(); j++) {
if (str.contains(sub.substring(i, j)) && j - i > max) {
max = j - i;
ans = sub.substring(i, j);
}
}
}
System.out.println(ans);
}
}
2、动态规划
分治思想:问题化解,大问题划成小问题,先解决小问题,再用小问题的解推导大问题的解
四个要素:
状态 --> 问题中抽象状态
状态转移方程
状态初始化
返回值
状态:
问题:两个字符串中的最长公共子串
子问题:a 的子串 和 b 的子串中 最长公共子串
抽象子问题:a 的前 i 个字符 和 b 的前 j个字符中,他们最长公共子串
a 的前 i 个字符和 b 的前 j 个字符中最长公共子串的长度,如果要知道最长公共子串具体内容:长度,起始位置,结束位置
F(i, j):以a的第i个字符结尾的子串和以b的第j个字符的子串,其最长公共子串的长度
转移方程: 如果 a 的第 i 个字符和 b 的第 j 个字符
相同:F(i, j) = F(i - 1, j - 1) + 1
不相同:0
以前一个小问题解为依据,举例:
起始位置:i - maxLen
= 4 - 4 = 0
初始状态:F(0, 0) = 0 -> 以 a 的第 0 个字符结尾的子串和以 b 的第 0 个字符的子串,其最长公共子串的长度
返回值:最长子串的内容
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s1 = scanner.nextLine();
String s2 = scanner.nextLine();
if (s1.length() < s2.length()) { // 题目要求以短的计算
System.out.println(getLongSubstring(s1, s2));
} else {
System.out.println(getLongSubstring(s2, s1));
}
}
private static String getLongSubstring(String s1, String s2) {
int endIndex = 0;
int max = 0;
int[][] dp = new int[s1.length() +1][s2.length() + 1];
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
// 如果 a 的第 i 个字符和 b 的第 j 个字符 相等
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j -1] + 1;
// 比 max 大,更新结果
if (max < dp[i][j]) {
max = dp[i][j];
endIndex = i;
}
}
}
}
return s1.substring(endIndex - max, endIndex);
}
}
给定两个只包含小写字母的字符串,计算两个字符串的最大公共子串的长度。
注:子串的定义指一个字符串删掉其部分前缀和后缀(也可以不删)后形成的字符串。
数据范围:字符串长度:1≤s≤150
进阶:时间复杂度:O(n3),空间复杂度:O(n)
输入描述:
输入两个只包含小写字母的字符串
输出描述:
输出一个整数,代表最大公共子串的长度
输入
asdfas
werasdfaswer
输出
6
【解题思路:】
和上一题相似:1、暴力解法
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s1 = scanner.nextLine();
String s2 = scanner.nextLine();
String str = s1.length() >= s2.length() ? s1 : s2;
String sub = s1.length() < s2.length() ? s1 : s2;
int max = 0;
for (int i = 0; i < sub.length(); i++) {
for (int j = i; j <= sub.length(); j++) {
if (str.contains(sub.substring(i, j)) && j - i > max) {
max = j - i;
}
}
}
System.out.println(max);
}
}
2、动态规划
状态转移方程:
第 i 个字符 != 第 j 个字符 F(i, j) = 0
第 i 个字符 == 第 j 个字符 F(i, j) = F(i - 1, j - 1) + 1
F(1,4): 1 a
F(2,5): F(1,4) + 1 --> 2 as
F(3, 6): F(2, 5) + 1 —> 3 asf
F(4, 7): F(3, 6) + 1 —> 4 asfd
初始状态:
返回值:
max(F(i, j)
import java.util.*;
public class Main {
// 状态F(ij):以第一个字符串第i个字符结尾和以第二个字符串第j个字符结尾的最大公共子串的长度
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s1 = scanner.nextLine();
String s2 = scanner.nextLine();
System.out.println(getMaxLenSubstring(s1, s2));
}
public static int getMaxLenSubstring(String s1, String s2) {
int[][] dp = new int[s1.length() + 1][s2.length() + 1];
int maxLen = 0;
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (maxLen < dp[i][j]) {
maxLen = dp[i][j];
}
} else {
dp[i][j] = 0;
}
}
}
return maxLen;
}
}
MP3 Player因为屏幕较小,显示歌曲列表的时候每屏只能显示几首歌曲,用户要通过上下键才能浏览所有的歌曲。为了简化处理,假设每屏只能显示4首歌曲,光标初始的位置为第1首歌。
现在要实现通过上下键控制光标移动来浏览歌曲列表,控制逻辑如下:
光标在第一首歌曲上时,按Up键光标挪到最后一首歌曲;光标在最后一首歌曲时,按Down键光标挪到第一首歌曲。
其他情况下用户按Up键,光标挪到上一首歌曲;用户按Down键,光标挪到下一首歌曲。
特殊翻页:屏幕显示的是第一页(即显示第 1 – 4 首)时,光标在第一首歌曲上,用户按Up键后,屏幕要显示最后一页(即显示第7-10首歌),同时光标放到最后一首歌上。同样的,屏幕显示最后一页时,光标在最后一首歌曲上,用户按Down键,屏幕要显示第一页,光标挪到第一首歌上。
一般翻页:屏幕显示的不是第一页时,光标在当前屏幕显示的第一首歌曲时,用户按Up键后,屏幕从当前歌曲的上一首开始显示,光标也挪到上一首歌曲。光标当前屏幕的最后一首歌时的Down键处理也类似。
其他情况,不用翻页,只是挪动光标就行。
数据范围:命令长度1≤s≤100 ,歌曲数量1≤n≤150
进阶:时间复杂度:O(n) ,空间复杂度:O(n)
输入描述:
输入说明:
1 输入歌曲数量
2 输入命令 U或者D
输出描述:
输出说明
1 输出当前列表
2 输出当前选中歌曲
输入
10
UUUU
输出
7 8 9 10
7
此题注意读题:特殊情况:屏幕显示最后一页时,光标在最后一首歌曲上,用户按Down键,屏幕要显示第一页,光标挪到第一首歌上。一般翻页:屏幕显示的不是第一页时,光标在当前屏幕显示的第一首歌曲时,用户按Up键后,屏幕从当前歌曲的上一首开始显示,光标也挪到上一首歌曲。
import java.util.*;
public class Main {
public static void mp3Index(int n, String s) {
int index = 1; // 起始页光标,大于 4 的多页记录,用于打印
int cur = 1; // 当前歌曲序号
// 一页或多页:
if (n <= 4) {
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (cur == 1 && c == 'U') { // 特殊翻页:第一首 Up
cur = n;
} else if(cur == n && c == 'D') { // 特殊翻页:最后一首 Down
cur = 1;
} else if (c == 'U') { // 其他情况:非收尾 光标上调
cur--;
} else { // 其他情况:光标下调
cur++;
}
}
} else {
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (index == 1 && cur == 1 && c == 'U') { // 特殊翻页:光标在第一页 第一首 Up
index = n - 3; // 屏幕显示最后一页(即显示第7-10首歌)-> 来到最后一页的起始位置
cur = n; // 光标放到最后一首歌上
} else if (index == n - 3 && cur == n && c == 'D') { // 特殊翻页(滚动):光标在最后一页 最后一首 Down
index = 1; // 屏幕要显示第一页,
cur = 1; // 光标挪到第一首歌上
} else if (index != 1 && cur == index && c == 'U') { // 一般翻页(滚动):不是第一页,光标在当前屏幕的第一首,Up
index--; // 屏幕从当前歌曲的 上一首 开始显示
cur--; // 光标挪到上一首
} else if (index != n - 3 && cur == index + 3 && c == 'D') { // 一般翻页:不是最后一页,光标在当前屏幕的最后一首,Down
index++; // 屏幕从当前歌曲的 下一首 开始显示
cur++; // 光标挪到下一首
} else if (c == 'U') { // 其他情况:不需要翻页,光标上调
cur--;
} else { // 其他情况:不需要翻页,光标下调
cur++;
}
}
}
// 打印:当前页歌曲 和 当前个歌曲序号
if (n <= 4) {
for (int i = 0; i < n; i++) {
if (i == 0) {
System.out.print(index);
} else {
System.out.print(" " + (index + i));
}
}
} else {
for (int i = 0; i < 4; i++) {
System.out.print((index + i) + " ");
}
}
System.out.println();
System.out.println(cur); // 当前歌曲序号
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextInt()) {
int n = scanner.nextInt(); // 歌曲数目
String s = scanner.next(); // (next) 操作命令 U / D
mp3Index(n, s);
}
}
}
洗牌在生活中十分常见,现在需要写一个程序模拟洗牌的过程。 现在需要洗2n张牌,从上到下依次是第1张,第2张,第3张一直到第2n张。首先,我们把这2n张牌分成两堆,左手拿着第1张到第n张(上半堆),右手拿着第n+1张到第2n张(下半堆)。接着就开始洗牌的过程,先放下右手的最后一张牌,再放下左手的最后一张牌,接着放下右手的倒数第二张牌,再放下左手的倒数第二张牌,直到最后放下左手的第一张牌。接着把牌合并起来就可以了。 例如有6张牌,最开始牌的序列是1,2,3,4,5,6。首先分成两组,左手拿着1,2,3;右手拿着4,5,6。在洗牌过程中按顺序放下了6,3,5,2,4,1。把这六张牌再次合成一组牌之后,我们按照从上往下的顺序看这组牌,就变成了序列1,4,2,5,3,6。 现在给出一个原始牌组,请输出这副牌洗牌k次之后从上往下的序列。
输入描述:
第一行一个数T(T ≤ 100),表示数据组数。对于每组数据,第一行两个数n,k(1 ≤ n,k ≤ 100),接下来有2n行个数a1,a2,...,a2n(1 ≤ ai ≤ 1000000000)。表示原始牌组从上到下的序列。
输出描述:
对于每组数据,输出一行,最终的序列。数字之间用空格隔开,不要在行末输出多余的空格。
输入
3
3 1
1
2
3
4
5
6
3 2
1
2
3
4
5
6
2 2
1
1
1
1
输出
1 4 2 5 3 6
1 5 4 3 2 6
1 1 1 1
1、两个 list1,list2 存放左右手的牌,按照题目要求洗牌,用一个 card 保存,更新左右手的牌,注意是逆序
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
// t 组计算:
while (t-- != 0) {
int n = scanner.nextInt();
int k = scanner.nextInt();
List<Integer> card = new ArrayList<>();
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
for (int i = 0; i < n; i++) {
list1.add(scanner.nextInt());
}
for (int i = 0; i < n; i++) {
list2.add(scanner.nextInt());
}
// k 次洗牌:
while (k-- != 0) {
// 洗牌放入 card
card.clear(); //
for (int i = n - 1; i >= 0; i--) {
card.add(list2.get(i)); // 先右
card.add(list1.get(i)); // 后左
}
// 更新 左 右 手的牌
list1.clear();
list2.clear();
int tmp = 2 * n - 1; // 洗完牌后也要逆序
for (int i = n - 1; i >= 0; i--) {
list1.add(card.get(tmp--)); // 左手前半部分 (2n-1, n)
list2.add(card.get(i)); // 右手后半部分 (n-1, 0)
}
}
// 打印 card:
for (int i = 2 * n - 1; i >= 0; i--) { // 倒序输出
System.out.print(card.get(i));
if (i != 0) { // 最后一个没有空格
System.out.print(" ");
}
}
System.out.println();
}
}
}
2、找规律:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
// t 组计算:
while (t-- != 0) {
int n = scanner.nextInt();
int k = scanner.nextInt();
int[] cards = new int[2 * n];
for (int i = 0; i < 2 * n; i++) {
cards[i] = scanner.nextInt();
}
playCard(cards, n, k);
}
}
private static void playCard(int[] cards, int n, int k) {
// k 洗牌
while (k-- != 0) {
int[] newCards = new int[2 * n];
// 左手 i -> 2 * i
// 右手 i + n -> 2 * i + 1
for (int i = 0; i < n; i++) { // 先右手 后左手
newCards[2 * i] = cards[i];
newCards[2 * i + 1] = cards[i + n];
}
cards = newCards; // 一次洗牌完成
}
// 打印
for (int i = 0; i < 2 * n - 1; i++) {
System.out.print(cards[i] + " ");
}
System.out.println(cards[2 * n - 1]); // 最后一次没有空格 换行
}
春节期间小明使用微信收到很多个红包,非常开心。在查看领取红包记录时发现,某个红包金额出现的次数超过了红包总数的一半。请帮小明找到该红包金额。写出具体算法思路和代码实现,要求算法尽可能高效。
给定一个红包的金额数组 gifts 及它的大小 n ,请返回所求红包的金额。
若没有金额超过总数的一半,返回0。
数据范围: 1≤n≤1000 1 ,红包金额满足 1≤gifti≤100000 1
输入
[1,2,3,2,2],5
输出
2
import java.util.*;
public class Gift {
public int getValue(int[] gifts, int n) {
// write code here
int cand = 0;
int count = 0;
int ret = 0; // 保存次数 最后比较 大于一半 就有答案
for (int i = 0; i < n; i++) {
if (count == 0) {
cand = gifts[i]; // 换候选人
ret = 0; // 新候选人的次数
}
if (cand == gifts[i]) {
count++;
ret++;
} else {
count--;
}
}
return ret > n / 2 ? cand : 0;
}
}
Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。编辑距离的算法是首先由俄国科学家 Levenshtein 提出的,故又叫 Levenshtein Distance 。
例如:
字符串A: abcdefg
字符串B: abcdef
通过增加或是删掉字符 ”g” 的方式达到目的。这两种方案都需要一次操作。把这个操作所需要的次数定义为两个字符串的距离。
要求:
给定任意两个字符串,写出一个算法计算它们的编辑距离。
数据范围:给定的字符串长度满足 1≤len(str)≤1000
输入描述:
每组用例一共2行,为输入的两个字符串
输出描述:
每组用例输出一行,代表字符串的距离
示例1
输入
abcdefg
abcdef
输出
1
与此题相同:
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
// 初始化
for (int i = 0; i <= word1.length(); i++) {
dp[i][0] = i;
}
for (int j = 0; j <= word2.length(); j++) {
dp[0][j] = j;
}
// dp[0][0] = 0; // 空串到空串 不需要操作
// for (int j = 1; j <= word2.length(); j++) {
// dp[0][j] = dp[0][j - 1] + 1; // 前一个加一
// }
// for (int i = 1; i <= word1.length(); i++) {
// dp[i][0] = dp[i - 1][0] + 1; // 上一个加一
// }
// 动态转移
// 删除 更新 添加
for (int i = 1; i <= word1.length(); i++) {
char c1 = word1.charAt(i - 1);
for (int j = 1; j <= word2.length(); j++) {
char c2 = word2.charAt(j - 1);
if (c1 == c2) { // 相等 直接左上角拿过来
dp[i][j] = dp[i - 1][j - 1];
} else { // 不相等 三个操作取最小值 加一
// 删除 插入 替换
dp[i][j] = minOfThree(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
}
}
}
return dp[word1.length()][word2.length()];
}
private static int minOfThree(int a, int b, int c) {
return Math.min(a, Math.min(b, c));
}
}