Java面试常见算法题
1、实现字符串反转
提供七种方案实现字符串反转
import java.util.Stack; public class StringReverse { public static String reverse1(String s) { int length = s.length(); if (length <= 1) return s; String left = s.substring(0, length / 2); String right = s.substring(length / 2, length); return reverse1(right) + reverse1(left); } public static String reverse2(String s) { int length = s.length(); String reverse = ""; for (int i = 0; i < length; i++) reverse = s.charAt(i) + reverse; return reverse; } public static String reverse3(String s) { char[] array = s.toCharArray(); String reverse = ""; for (int i = array.length - 1; i >= 0; i--) reverse += array[i]; return reverse; } public static String reverse4(String s) { return new StringBuffer(s).reverse().toString(); } public static String reverse5(String orig) { char[] s = orig.toCharArray(); int n = s.length - 1; int halfLength = n / 2; for (int i = 0; i <= halfLength; i++) { char temp = s[i]; s[i] = s[n - i]; s[n - i] = temp; } return new String(s); } public static String reverse6(String s) { char[] str = s.toCharArray(); int begin = 0; int end = s.length() - 1; while (begin < end) { str[begin] = (char) (str[begin] ^ str[end]); str[end] = (char) (str[begin] ^ str[end]); str[begin] = (char) (str[end] ^ str[begin]); begin++; end--; } return new String(str); } public static String reverse7(String s) { char[] str = s.toCharArray(); Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < str.length; i++) stack.push(str[i]); String reversed = ""; for (int i = 0; i < str.length; i++) reversed += stack.pop(); return reversed; } }
2、将一个正整数分解质因数
/*将一个正整数分解质因数 * 每个合数都可以写成几个质数相乘的形式,这几个质数就都叫做这个合数的质因数 */ primeFactor(); } /* * 程序分析:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成: * (1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。 * (2)如果n>=k,但n能被k整除,则应打印出k的值,并用n除以k的商,作为新的正整数你n,重复执行第一步。 * (3)如果n不能被k整除,则用k+1作为k的值,重复执行第一步。 */ public static void primeFactor() {// 该方法将一个正整数分解成质因数相乘的形式 Scanner scan = new Scanner(System.in);// 接收控制台输入的信息 System.out.print("请输入一个正整数:"); try { int num = scan.nextInt();// 取出控制台输入的信息 if (num < 2) {// 若输入的数小于2,输出提示信息 System.out.println("必须输入不小于2的正整数!"); } else { int primeNumber = 2;// 定义最小的质数 System.out.print(num + " = "); while (primeNumber <= num) {// 在质数小于输入的数时,进行循环 if (primeNumber == num) {// 当质数等于输入的数时,直接输出 System.out.print(num); break;// 跳出循环 } else if (num % primeNumber == 0) {// 当输入的数与质数的余数为0时,输出这个质数 System.out.print(primeNumber + " * "); num = num / primeNumber;// 把剩下的结果赋给num } else {// 在余数不为0时,质数递增 primeNumber++; } } } } catch (Exception e) { System.out.println("必须输入正整数!");// 捕捉异常,输出必须输入整数 }
3、有一段文本,统计其中的单词数 注意:单词间的间隔不一定是一个空格
@Test1 public void Test1() { int count = 0; String sentence ="I am Geng.X.y,she is my girlfriend.Lowood?what is that?"; Scanner s = new Scanner(sentence).useDelimiter(" |,|\\?|\\."); while(s.hasNext()){ count++; System.out.println(s.next()); } System.out.println("这段短文单词的个数是:"+count); String[] strs = {"a", "b", "c"}; for (String str:strs) { change(str); System.out.println(str); } }
4、计算字符串中单词出现的次数
@Test public void test1() { String str = "i am god god god"; if (str == null) System.out.println("null"); str = str.trim(); int len = str.length(); if (len == 0) System.out.println("null"); Map<String, int[]> map = new HashMap<String, int[]>();//用int[]代替了integer,避免了Integer在使用过程中的自动装箱和拆箱,提高了效率 String[] words = str.split("\\s+"); for (int i = 0; i < words.length; i++) { int[] counts = new int[1]; if (!map.containsKey(words[i])) { counts[0] = 1; map.put(words[i], counts); } else { counts[0] = map.get(words[i])[0] + 1; map.put(words[i], counts); } } System.out.println(map.get("god")[0]); }
5、统计字符串中字母最多的单词
@Test public void test() { String str = "abcdefg123456789asdfgagfafg"; int max = 0; int count = 0; String temp = ""; for (int i = 0; i < str.length(); i++) { String substring = str.substring(i, i + 1); if (substring.matches("[a-z]||[A-Z]")) { count++; temp += substring; if (max < count) { max = count; } } else { count = 0; temp = ""; } } System.out.println(max + "," + temp); }
6、将一个链表倒序
public class SingleLinkedReverse { class Node { int data; Node next; public Node(int data) { this.data = data; } } public static void main(String[] args) { SingleLinkedReverse slr = new SingleLinkedReverse(); Node head, tail; head = tail = slr.new Node(0); for (int i = 1; i < 10; i++) { Node p = slr.new Node(i); tail.next = p; tail = p; } tail = head; while (tail != null) { System.out.print(tail.data); tail = tail.next; } head = reverse(head); System.out.println(); while (head != null) { System.out.print(head.data); head = head.next; } } private static Node reverse(Node head) { Node p1, p2 = null; p1 = head; while (head.next != null) { p2 = head.next; head.next = p2.next; p2.next = p1; p1 = p2; } return p2; } }
7、生成随机字符串,字符串必须同时包含大小写字母和数字
public class RandomAlphaNumericGenerator { private static final char[] symbols; private final Random random = new Random(); private final char[] buf; static { StringBuilder tmp = new StringBuilder(); for (char ch = '0'; ch <= '9'; ++ch) tmp.append(ch); for (char ch = 'a'; ch <= 'z'; ++ch) tmp.append(ch); for (char ch = 'A'; ch <= 'Z'; ++ch) tmp.append(ch); // 添加一些特殊字符 tmp.append("!@#$%"); symbols = tmp.toString().toCharArray(); } public RandomAlphaNumericGenerator(int length) { if (length < 1) throw new IllegalArgumentException("length < 1: " + length); buf = new char[length]; } public String nextString() { for (int idx = 0; idx < buf.length; ++idx) buf[idx] = symbols[random.nextInt(symbols.length)]; return new String(buf); } public static void main(String[] args) { RandomAlphaNumericGenerator randomTest = new RandomAlphaNumericGenerator(11); System.out.println(randomTest.nextString()); for(int i=0;i<10;i++){ String result = null; do { result = randomTest.nextString(); } while (!result.matches(".*(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%]).*")); System.out.println(result); } System.out.println(); } }
8、七进制转十进制
public void test3() {
int num = 0;
String src = "125";
char[] c = src.toCharArray();
for (int i=0; i<c.length; i++) {
num = (num << 3) - num; //也就是 num *= 7;
num += (c[i]-'0');
}
System.out.println(num);
String a=Integer.valueOf("125", 8).toString();
System.out.println(a);
}
9、迷宫算法
package com.maze; /** * Created by Genesis on 2017/2/8. */ public class MiGong { /** * 定义迷宫数组 */ private int[][] array = { {0, 0, 1, 0, 0, 0, 1, 0}, {0, 0, 1, 0, 0, 0, 1, 0}, {0, 0, 1, 0, 1, 1, 0, 1}, {0, 1, 1, 1, 0, 0, 1, 0}, {0, 0, 0, 1, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 1, 0, 1}, {0, 1, 1, 1, 1, 0, 0, 1}, {1, 1, 0, 0, 0, 1, 0, 1}, {1, 1, 0, 0, 0, 0, 0, 0} }; private int maxLine = 8; private int maxRow = 9; public static void main(String[] args) { System.out.println(System.currentTimeMillis()); new MiGong().check(0, 0); System.out.println(System.currentTimeMillis()); } private void check(int i, int j) { //如果到达右下角出口 if (i == maxRow - 1 && j == maxLine - 1) { print(); return; } //向右走 if (canMove(i, j, i, j + 1)) { array[i][j] = 5; check(i, j + 1); array[i][j] = 0; } //向左走 if (canMove(i, j, i, j - 1)) { array[i][j] = 5; check(i, j - 1); array[i][j] = 0; } //向下走 if (canMove(i, j, i + 1, j)) { array[i][j] = 5; check(i + 1, j); array[i][j] = 0; } //向上走 if (canMove(i, j, i - 1, j)) { array[i][j] = 5; check(i - 1, j); array[i][j] = 0; } } private boolean canMove(int i, int j, int targetI, int targetJ) { // System.out.println("从第" + (i + 1) + "行第" + (j + 1) + "列,走到第" + (targetI + 1) + "行第" + (targetJ + 1) + "列"); if (targetI < 0 || targetJ < 0 || targetI >= maxRow || targetJ >= maxLine) { // System.out.println("到达最左边或最右边,失败了"); return false; } if (array[targetI][targetJ] == 1) { // System.out.println("目标是墙,失败了"); return false; } //避免在两个空格间来回走 if (array[targetI][targetJ] == 5) { // System.out.println("来回走,失败了"); return false; } return true; } private void print() { System.out.println("得到一个解:"); for (int i = 0; i < maxRow; i++) { for (int j = 0; j < maxLine; j++) { System.out.print(array[i][j] + " "); } System.out.println(); } } }
10、四舍五入
方法一、 Math.round(12.5) 方法二、 double f = 111231.5585; BigDecimal b = new BigDecimal(f); double f1 = b.setScale(2, RoundingMode.HALF_UP).doubleValue();
11、生成随机数
Random r = new Random(); a 、生成[0,1.0)区间的小数 double d1 = r.nextDouble(); 直接使用nextDouble方法获得。 b、生成[0,5.0)区间的小数 double d2 = r.nextDouble() * 5; c、生成[1,2.5)区间的小数 [n1,n2] double d3 = r.nextDouble() * 1.5 + 1;【也就是 r.nextDouble() * (n2-n1)+n1】
12、在一个字符串中查找第一个非重复的字符
第一个算法实现在getFirstNonRepeatedChar(String str)方法中。它首先获得字符串的字符数组,然后遍历数组并建立一个哈希表,哈希表的键为字符,值为该字符出现的次数。下一步它会遍历LinkedHashMap去找到第一个值为1的元素,那便是第一个非重复的字符,因为LinkedHashMap维护的元素顺序与插入顺序一致,而我们遍历字符数组是从头遍历到尾。这种算法的缺点在于它需要两个循环,第一个循环的次数与字符串的字符个数成正比,而第二个循环的次数与字符串中重复的字符个数成正比。最差的情况是非重复的字符出现在字符串的最尾部,那么这个算法需要2*N的时间去解决这个问题。
第二个算法实现在firstNonRepeatingChar(String word)方法中。这种解决方案可以在一次字符串扫描中找到第一个不重复的字符,它应用了典型的空间时间权衡技术。它使用了两个存储空间来减少一次循环,是标准的空间-时间折衷。由于我们将重复和不重复的字符分开存放,在循环结束后,存放不重复字符的列表中的第一个元素就是我们所要找的第一个非重复字符。这种解决方案稍微优于上一种。如果在字符串中没有不重复的字符,你可以选择返回null或者空字符串。
public class Programming { public static char getFirstNonRepeatedChar(String str) { Map<Character, Integer> counts = new LinkedHashMap<Character, Integer>( str.length()); for (char c : str.toCharArray()) { counts.put(c, counts.containsKey(c) ? counts.get(c) + 1 : 1); } for (Entry<Character, Integer> entry : counts.entrySet()) { if (entry.getValue() == 1) { return entry.getKey(); } } throw new RuntimeException("didn't find any non repeated Character"); }
public static char firstNonRepeatingChar(String word) { Set<Character> repeating = new HashSet<Character>(); List<Character> nonRepeating = new ArrayList<Character>(); for (int i = 0; i < word.length(); i++) { char letter = word.charAt(i); if (repeating.contains(letter)) { continue; } if (nonRepeating.contains(letter)) { nonRepeating.remove((Character) letter); repeating.add(letter); } else { nonRepeating.add(letter); } } return nonRepeating.get(0); }