您现在的位置是:首页 >技术教程 >数据结构与算法-阿里Java开发实习生的面试题(从易到难)网站首页技术教程
数据结构与算法-阿里Java开发实习生的面试题(从易到难)
面试题目:
- 编写一个Java程序,求1~100内的所有偶数的和。
- 编写一个Java程序,找出一个数组中的最大值。
- 编写一个Java程序,实现冒泡排序。
- 编写一个Java程序,统计一个字符串中每个单词出现的次数。
- 编写一个Java程序,实现快速排序。
- 编写一个Java程序,实现二分查找。
- 编写一个Java程序,实现斐波那契数列。
- 编写一个Java程序,实现字符串匹配。
- 编写一个Java程序,实现求解逆波兰表达式的值。
题目解析:
编写一个Java程序,求1~100内的所有偶数的和。
public class SumOfEvenNumbers {
public static void main(String[] args) {
int sum = 0;
for (int i = 2; i <= 100; i += 2) {
sum += i;
}
System.out.println("1~100内的所有偶数的和为:" + sum);
}
}
注释:首先定义一个变量sum表示求和结果,初始化为0。
然后通过一个for循环,从2开始每次加2遍历到100,即i从2开始,每次加2,最大到100。
在循环体中,将当前的偶数i加到sum中。
最后输出结果。
编写一个Java程序,找出一个数组中的最大值。
import java.util.Arrays;
public class MaxNumberInArray {
public static void main(String[] args) {
int[] array = {1, 5, 2, 10, 3, 8};
System.out.println("数组中的最大值为:" + Arrays.stream(array).max().getAsInt());
}
}
注释:首先,定义了一个整型数组array,包含了一些数字。
然后,调用了Arrays.stream(array)方法将数组转换为一个IntStream流。
接着,使用max()方法找出流中的最大值。
最后,使用getAsInt()方法将IntStream流转换为int值,并打印输出结果。
程序输出了数组中的最大值。本例中,数组中最大的数字是10。
编写一个Java程序,实现冒泡排序。
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] array = {1, 5, 2, 10, 3, 8};
for (int i = array.length - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
System.out.println("冒泡排序后的数组为:" + Arrays.toString(array));
}
}
注释:冒泡排序的原理:从数组的第一个元素开始与下一个元素进行比较,如果比下一个元素大,就交换位置,一轮下来会将最大的元素“冒泡”到数组末尾,然后再从头到倒数第二个元素重复上述操作,直到整个数组排序完成。
在本程序中,先定义了一个整型数组array并初始化,然后使用两个for循环对该数组进行冒泡排序。第一个for循环控制排序轮数,每次排序将会将一个最大的元素放到数组末尾。第二个for循环控制每轮排序中相邻两个元素的比较和交换,采用if条件判断,如果前面的元素大于后面的元素,则交换它们的位置。
最后使用Arrays.toString()方法将排序后的数组打印输出。
编写一个Java程序,统计一个字符串中每个单词出现的次数。
import java.util.HashMap;
import java.util.Map;
public class CountWordsInString {
public static void main(String[] args) {
String str = "hello world, hello java, java programming";
String[] words = str.split("[\s\p{Punct}]+");
Map<String, Integer> map = new HashMap<>();
for (String word : words) {
if (map.containsKey(word)) {
map.put(word, map.get(word) + 1);
} else {
map.put(word, 1);
}
}
System.out.println("统计每个单词出现的次数为:" + map);
}
}
注释:以上代码是一个统计字符串中单词出现次数的示例。主要思路是将字符串按照空格和标点符号进行分割为单词数组,然后通过HashMap来统计每个单词出现的次数。遍历单词数组,如果Map中已存在该单词,则将它的值加1;否则在Map中加入该单词,并将它的值初始化为1。最后输出Map中统计得到的每个单词出现次数。
编写一个Java程序,实现快速排序。
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] array = {1, 5, 2, 10, 3, 8};
quickSort(array, 0, array.length - 1);
System.out.println("快速排序后的数组为:" + Arrays.toString(array));
}
public static void quickSort(int[] array, int left, int right) {
if (left >= right) {
return;
}
int pivotIndex = partition(array, left, right);
quickSort(array, left, pivotIndex - 1);
quickSort(array, pivotIndex + 1, right);
}
public static int partition(int[] array, int left, int right) {
int pivot = array[left];
int i = left, j = right;
while (i < j) {
while (i < j && array[j] >= pivot) {
j--;
}
if (i < j) {
array[i++] = array[j];
}
while (i < j && array[i] <= pivot) {
i++;
}
if (i < j) {
array[j--] = array[i];
}
}
array[i] = pivot;
return i;
}
}
注释:这段代码实现了快速排序算法。快速排序的思想是选择一个基准值(pivot),将数组中大于或等于基准值的元素放在基准值的右侧,将小于或等于基准值的元素放在基准值的左侧,然后递归地对左右两侧的子数组进行排序,直到子数组的长度为1,排序完成。
代码中的quickSort方法就是实现了上述算法的递归过程,当left>=right时就不再进行排序,否则将数组划分为左右两个子数组,并递归对其进行排序。
partition方法就是实现了基准值的选择和子数组的划分。具体地,从左端开始扫描数组,找到第一个小于或等于基准值的元素,将其放在左侧;然后从右端开始扫描数组,找到第一个大于或等于基准值的元素,将其放在右侧;重复上述过程直到左右指针相遇,最后将基准值放在相遇位置,即左右子数组的分界点上,返回分界点的位置作为下一轮递归的基准值。
编写一个Java程序,实现二分查找。
public class BinarySearch {
public static void main(String[] args) {
int[] array = {1, 2, 3, 5, 8, 10};
int key = 5;
int index = binarySearch(array, key);
System.out.println("关键字" + key + "在数组中的位置为:" + index);
}
public static int binarySearch(int[] array, int key) {
int left = 0, right = array.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] == key) {
return mid;
} else if (array[mid] < key) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}
注释:这段代码实现了二分查找算法,也称作折半查找。该算法要求输入的数组必须有序。先将数组的左端点和右端点指定为left和right,然后计算中间位置mid,比较中间位置和目标值的大小,如果它等于目标值,则查找结束,返回mid。如果它小于目标值,则说明目标值在mid右边,需要将left指向mid+1的位置,再次进行查找。如果它大于目标值,则说明目标值在mid左边,需要将right指向mid-1的位置,再次进行查找。直到left大于right时,说明目标值不存在于数组中,查找失败,返回-1。最后,在main函数中调用binarySearch函数,在数组中查找关键字key,并输出其位置。
编写一个Java程序,实现斐波那契数列。
public class Fibonacci {
public static void main(String[] args) {
int n = 10;
for (int i = 1; i <= n; i++) {
System.out.print(fibonacci(i) + " ");
}
}
public static int fibonacci(int n) {
if (n <= 2) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
注释:该代码实现了斐波那契数列的计算和输出,斐波那契数列是一个数列,由0或1开始,之后的每一项都是前两项之和。
在该代码中,定义了一个主函数main,其中n的值为10,表示计算并输出斐波那契数列的前10个数,通过for循环逐一输出。
同时,该代码还定义了一个静态方法fibonacci用来计算斐波那契数列中第n个数的值。在该方法中,若n小于等于2,则返回1,否则递归调用fibonacci(n-1)和fibonacci(n-2)并将结果相加返回。
编写一个Java程序,实现字符串匹配。
public class StringMatching {
public static void main(String[] args) {
String str = "hello world, hello java, java programming";
String pattern = "java";
System.out.println("字符串" + pattern + "在" + str + "中的位置为:" + stringMatching(str, pattern));
}
public static int stringMatching(String str, String pattern) {
int n = str.length(), m = pattern.length();
for (int i = 0; i <= n - m; i++) {
boolean flag = true;
for (int j = 0; j < m; j++) {
if (str.charAt(i + j) != pattern.charAt(j)) {
flag = false;
break;
}
}
if (flag) {
return i;
}
}
return -1;
}
}
注释:这段代码是一个字符串匹配算法的实现。具体来说,它的功能是在一个字符串中查找一个给定的子串,找到了就返回子串在原字符串中第一次出现的位置,否则返回 -1。
在代码中,首先定义了一个主函数,它创建了一个字符串 str 和一个匹配模式 pattern,然后调用了 stringMatching 函数进行匹配并输出匹配结果。
在 stringMatching 函数中,首先获取原字符串和模式串的长度,然后通过两层循环进行匹配。外层循环控制原字符串的位置,内层循环对比当前位置起始的 m 个字符是否与模式串相同,如果出现了不相同的字符就将 flag 标记为 false,并退出内层循环。如果最后 flag 仍为 true 就表示匹配成功,返回当前位置 i,否则继续向后匹配。如果遍历完整个原字符串都没有匹配成功,就返回 -1。
这种字符串匹配算法的时间复杂度为 O(nm),其中 n 是原字符串长度,m 是模式串长度。在实际使用时,可能需要考虑更高效的字符串匹配算法,比如 KMP 算法、Boyer-Moore 算法等。
编写一个Java程序,实现求解逆波兰表达式的值。
import java.util.Stack;
public class ReversePolishNotation {
public static void main(String[] args) {
String[] tokens = {"2", "1", "+", "3", "*"};
System.out.println("逆波兰表达式求解的结果为:" + evaluate(tokens));
}
public static int evaluate(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (String token : tokens) {
if (token.equals("+")) {
stack.push(stack.pop() + stack.pop());
} else if (token.equals("-")) {
int a = stack.pop(), b = stack.pop();
stack.push(b - a);
} else if (token.equals("*")) {
stack.push(stack.pop() * stack.pop());
} else if (token.equals("/")) {
int a = stack.pop(), b = stack.pop();
stack.push(b / a);
} else {
stack.push(Integer.parseInt(token));
}
}
return stack.pop();
}
}
注释: 逆波兰表达式是一种将表达式中的运算符放在操作数之后的表达方式。程序的主方法中,给定了一个逆波兰表达式,即 tokens 数组为 {“2”, “1”, “+”, “3”, “*”},表示 2+1 * 3,程序将求解这个表达式的结果并输出。
程序中的 evaluate 方法接受一个字符串数组 tokens 作为参数,并使用一个栈来实现逆波兰表达式的求解。遍历 tokens 中的每个元素,如果是运算符,就从栈中弹出两个数执行相应的运算后再将结果压回栈中;如果是数字,就将其转换成整数并入栈。
最后,栈中仅剩一个元素,即逆波兰表达式的求解结果,将其弹出并作为方法的返回值。
需要注意的是,程序中的四则运算符只支持整数运算,并且除法是整除运算。
总结:
学习以上面试题,需要熟练掌握Java基本语法和数据结构算法,并要有较强的编程思维能力和解决问题的能力。在实现算法时,需要注意算法的时间复杂度和空间复杂度,以及合理使用Java类库中的函数和数据结构,提高程序的效率和可读性。以上九道题覆盖了基本的算法和数据结构,掌握了这些,可以在面试中对算法和数据结构的相关问题进行较好的回答。