程序基础练习1
codewar和leetcode
编程练习网站codewars是一个练习编程题目的网站,对于编程练习网站,我们已经很熟悉了leetcode,不过leetcode
是非常侧重算法的,而codewars
是侧重程序应用本身的,对于了解程序的本身而言,codewars
是更加适合的,等熟练掌握以后,进阶可以去练习leetcode
,在很长一段时间,我都将以熟练使用程序本身为目的,所以从基础打起
1. 创造数组
1
2
3
4
5
6
7
8
9
10
11
// Add the value "codewars" to the array websites 1,000 times.
public class KataExampleTwist
{
public static String[] kataExampleTwist()
{
String[] websites = {};
return websites;
}
}
这是最简单的一道题,给websites
数组添加1000个字符串codewars
1
2
3
4
5
6
7
8
9
10
11
12
13
// Add the value "codewars" to the array websites 1,000 times.
import java.util.*;
public class KataExampleTwist
{
public static String[] kataExampleTwist()
{
String[] websites = new String[1000];
Arrays.fill(websites,"codewars");
return websites;
}
}
实现的方式很多,可以通过Arrays.fill
方法添加,也可以直接循环赋值
1
2
3
4
5
6
7
8
9
10
11
public class KataExampleTwist
{
public static String[] kataExampleTwist()
{
String[] websites = new String[1000];
for(int i = 0; i < 1000; i++)
websites[i] = "codewars";
return websites;
}
}
当然,还有很多其他方式,这都是考察基础的东西
动态语言
在直接应用上,动态语言还是要方便不少,还是用我熟悉的ruby
来比较一下
1
websites = ["codewars"] * 1000
没错,不需要考虑数据类型,不需要考虑内存空间,不需要循环一个一个复制,数组甚至可以直接用乘法,它甚至知道乘法是把里面的元素弄成多个拷贝,用更加面向对象一点的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
websites = []
#1
1000.times{ websites << "codewars"}
#2
1000.times{ websites += ["codewars"]}
#3
1000.times{ websites.push("codewars")}
#4
websites = Array.new(1000, "codewars")
#5
websites = Array.new(1000){|_| "codewars"}
#6
websites = (1..1000).map{|_| "codewars"}
#7
websites = ("codewars " * 1000).split
可以看出,动态语言实现基本的数据逻辑是非常简单的,我这里随便写了7种ruby
的实现方式1-3是以数字1000
为对象实现的,4-5是以数组对象实现,6是以Range
对象实现,7是以字符串对象实现
对比
因为Java
是在学习中,所以以后也会拿几种语言来对比加深印象和理解,不同的语言大部分是相同的,少部分本身特点,结合起来学习会更加好理解
2. 字符串替换
题目是将一个字符串的小写aeiou
去掉,返回如下结果
1
2
3
4
"hello" --> "hll"
"codewars" --> "cdwrs"
"goodbye" --> "gdby"
"HELLO" --> "HELLO"
最直接最机械的方式
1
2
3
4
5
6
7
8
9
10
public class Kata {
public static String shortcut(String input) {
return input.replace("a","")
.replace("e","")
.replace("i","")
.replace("o","")
.replace("u","");
}
}
当然更直接更优雅的
1
2
3
4
5
public class Kata {
public static String shortcut(String input) {
return input.replaceAll("[aeiou]", "");
}
}
熟悉的ruby
方式
1
2
3
4
5
6
def shortcut(s)
#1
s.gsub(/[aeiou]/,"")
#2
s.tr("aeiou","")
end
3. 16进制转换10进制
题目:给定一个16进制的字符串,返回10进制的结果
1
2
3
4
5
6
7
public class Kata {
public static int hexToDec(final String hexString) {
return Integer.parseInt(hexString, 16);
}
}
1
2
3
def hex_to_dec(hex)
hex.to_i(16)
end
如果不熟悉的话,对于java
,需要从API
中java.lang.Integer
类中找到类静态方法,而ruby
是字符串的String
类的实例方法to_i
,从这几个例子来看,java
虽然也是OO
派的语言,但实际上使用还是有点函数式的思维,但是ruby
就不一样了,感觉OO
的形式最极致,写多了ruby
在换别的多少还是有点不适应
4. 类和实例
题目简介:返回一个数组,数组第一个是Man类型,第二个是Woman类型,男人和女人都属于Human的子类
1
2
3
4
5
6
7
8
9
10
11
12
public class God {
public static Human[] create(){
return new Human[]{new Man(), new Woman()};
}
}
class Human{
}
class Man extends Human{
}
class Woman extends Human{
}
这里是属于class
和继承最基本的概念,而且因为这里必须是在同一个文件中定义外部类,还涉及到一个文件中只有一个public
的知识点。所以定义的时候不加权限修饰符,当然这里还可以用abstract
和interface
来定义,这里就不用了
1
2
3
4
5
6
7
8
9
10
class Human
end
class Man < Human
end
class Woman < Human
end
def god
[Man.new, Woman.new]
end
当然从直接的语言感官来讲,还是ruby
更直观好理解一点
5.字符串计算操作符
题目描述:给一个函数3个参数(final double x, final String op, final double y),例如(6,”-“, 1.5),返回6 - 1.5,也就是4.5,其中计算符op不是”+-*/”则返回null,除法除以0也返回null
1
2
3
4
5
6
7
8
9
10
11
public class Calculator {
public static Double calculate(final double x, final String op, final double y) {
switch (op) {
case "+": return x + y;
case "-": return x - y;
case "*": return x * y + 0.0;
case "/": return y == 0 ? null : x / y;
}
return null;
}
}
这里有个有意思的地方就是对于”*“,为什么后面要加个0.0
多此一举?这就是练习基础的重要性,如果不加这个0.0
,则这道题的测试就会通不过,因为比如-1.0 * 0.0 = -0.0
,一般认为0是以正号形式存在,而-0.0 + 0.0 = 0.0
所以需要加个看起来没有意义的0.0
了,这就是一个非常不明显的大坑。
1
2
3
4
5
6
7
8
9
10
11
12
13
def calculate(x, op, y)
case op
when "+"
return x + y
when "-"
return x - y
when "*"
return x * y
when "/"
return y == 0 ? "null" : x / y
end
return "null"
end
对于动态语言,乘法则没有-0.0这种说法
6. 阶乘
题目描述:给定参数n,返回n的阶乘,要求n不小于0且n不大于12,否则抛,否则抛IllegalArgumentException异常,经典题目,可以用递归,也可以用迭代
1
2
3
4
5
6
public class Factorial {
public int factorial(int n) {
if(n < 0 || n > 12) throw new IllegalArgumentException("Illega params");
return n <= 1 ? 1 : n * factorial(n - 1);
}
}
这里用递归方法
7.首字母大写
题目描述:给一个字符串,返回首字母大写,其他字母小写
1
2
3
4
5
public class GreetMe{
public static String str_capital(String name){
return "Hello " + name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase();
}
}
这里主要需要使用substring
和toUppercase
toLowerCase
实例方法
1
2
3
def str_capital(name)
name.capitalize
end
动态语言直接封装了很多实例方法,如果对方法熟练度高的话非常方便
8. 矩阵相加
题目描述: 给定两个n*n的二维数组,要求返回每个位置相加的二位数组,例如 [[1,2],[3,4]],[[1,2],[3,4]],返回[[2,4],[6,8]]
1
2
3
4
5
6
7
8
9
10
11
public class Kata {
public static int[][] matrixAddition(int[][] a, int[][] b) {
for(int i=0; i<a.length; i++){
for(int j=0; j<a.length; j++){
a[i][j]+=b[i][j];
}
}
return a;
}
}
java
是直接自己用基本数据类型和循环实现
1
2
3
def matrixAddition(a, b)
a.zip(b).map { |el| el.transpose.map(&:sum) }
end
是的,动态语言就是这么简洁,但是简洁的代价是不好维护,里面用到了zip
,map
,transpose
,&:
,block
等非常多的知识点,其实里面的东西挺多的,以后再说了
9. 创建类
问题描述:给一个整数数组[width, length, height],要求创建block
类实现返回长宽高,面积,体积的方法,这个是属于最最基础的概念,但是我手写还是没做到一把过,还是会出错,所以还是值得记录理解下,而且每种语言的类的实现方式不一样,细节概念也不一样,可以做对比理解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Block{
private int width;
private int length;
private int height;
public Block(int[] arr){
width = arr[0];
length = arr[1];
height = arr[2];
}
public int getWidth(){
return width;
}
public int getLength(){
return length;
}
public int getHeight(){
return height;
}
public int getVolume(){
return width * length * height;
}
public int getSurfaceArea(){
return 2* (width * length + width * height + length * height);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Block
def initialize(args)
@width, @length, @height = args
end
def get_width
@width
end
def get_length
@length
end
def get_height
@height
end
def get_volume
@width * @length * @height
end
def get_surface_area
2 * (@width * @length + @width * @height + @length * @height)
end
end
可以看到,两个语言构造函数形式不一样,实例变量形式不一样,当然类变量和类方法这里没体现,getter
,setter
方法也是有区别的,这里也暂时没体现