面试题1.1:实现一个算法,确定一个字符串的所有字符是否全都不同。假使不允许使用额外的数据结构,又该如何处理?
注意:ASCII字符共有255个,其中0-127的字符有字符表
第一种解法:是《CC150》里面的解法
public static boolean checkDifferent(String iniString) { if(iniString == null || iniString.length() <= 0) return true; String newString = iniString.trim(); //去掉左右空格 int len = newString.length(); if(len > 256) return false; boolean[] char_set = new boolean[65536]; //256的牛客网会报数组越界 for(int i=0;i<len;i++){ int val = newString.charAt(i); //取得字符串每一个字符的ASCII码值 if(char_set[val] == true) //有val表示出现过 return false; char_set[val] = true; //表示ASCII为val的字符出现过了 } return true; }
第二种解法:先排序,然后通过异或运算判断是否有重复的字符
public static boolean checkDifferent(String iniString) { if(iniString == null || iniString.length() <= 0) return true; String newString = iniString.trim(); //去掉左右空格 int len = newString.length(); if(len > 256) return false; char[] sortedArr = newString.toCharArray(); Arrays.sort(sortedArr); for(int i=1;i<len;i++){ int a = sortedArr[i-1]; int b = sortedArr[i]; if((a^b) == 0) return false; } return true; }
面试题1.2:实现void reverse(char* str)函数,即反转一个null结尾的字符串
注意:不分配额外空间,直接就地反转字符串,注意nul字符
import java.util.*; public class Reverse { public String reverseString(String iniString) { // write code here StringBuffer Buf = new StringBuffer(); if(iniString == null || iniString.length() <=0) return Buf.toString(); int length = iniString.length(); for(int i=length-1;i>=0;i--){ Buf.append(iniString.charAt(i)); } return Buf.toString(); } }
面试题1.3:给定两个字符串,请编写程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串——《Leetcode》242. Valid Anagram
思路:变位词问题(anagram),注意是否区分大小写,是否考虑空白字符,如果两个字符串的长度不一样,那么就不可能变位词
解法1:对两个字符串的字符重新排序后,再组成字符串,然后equals两个字符串是否相等
package cc150; import java.util.Arrays; public class Anagram { public static void main(String[] args) { // TODO 自动生成的方法存根 String str1 = "CBA"; String str2 = "ABC"; System.out.println(anagram(str1, str2)); } public static String sort(String s){ char[] content = s.toCharArray(); Arrays.sort(content); return new String(content); //使用new String,toString是StringBuffer用的 } public static boolean anagram(String s1,String s2){ if(s1.length() != s2.length()) return false; return sort(s1).equals(sort(s2)); } }
解法2:建一个256大小的字符数组,然后在这个数组记录每个字母出现的次数,最后比较两个数组是否相等(比第一种慢,且占用空间多)(Leetcode用的类似这种)
package cc150; import java.util.Arrays; public class Anagram { public static void main(String[] args) { // TODO 自动生成的方法存根 String str1 = "CBA"; String str2 = "ABC"; System.out.println(anagram(str1, str2)); } public static boolean anagram(String s1,String s2){ if(s1.length() != s2.length()) return false; int[] Arr = new int[256]; char[] Arr1 = s1.toCharArray(); for(char c:Arr1){ Arr[c]++; } for(int i=0;i<s2.length();i++){ int c = (int) s2.charAt(i); if(--Arr[c] < 0) return false; } return true; } }
面试题1.4:编写一个方法,讲字符串中的空格全部替换为“%20”。假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的“真实”长度。(注:用Java实现的话,请使用字符数组实现,以便直接在数组上操作。)——《剑指Offer》P61
package cc150; public class ReplaceSpaces { public static void main(String[] args) { // TODO 自动生成的方法存根 String str = "AB C"; System.out.println(replaceSpace(str,5)); } public static String replaceSpace(String iniString, int length) { // write code here int spaceCount = 0; for(int i=0;i<length;i++){ if(iniString.charAt(i) == ' ') spaceCount++; } int newLength = length + spaceCount * 2; char[] newString = new char[newLength]; for(int i=length-1;i>=0;i--){ System.out.println(iniString.charAt(i) == ' '); if(iniString.charAt(i) == ' '){ newString[newLength-1] = '0'; newString[newLength-2] = '2'; newString[newLength-3] = '%'; newLength = newLength-3; }else{ newString[newLength-1] = iniString.charAt(i); newLength = newLength-1; } } StringBuffer buf = new StringBuffer(); newLength = length + spaceCount * 2; for(int i=0;i<newLength;i++) buf.append(newString[i]); return buf.toString(); } }
面试题1.5:利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩” 后的字符串没有变短,则返回原先的字符串。
package cc150; public class Zipper { public static void main(String[] args) { // TODO 自动生成的方法存根 String str = "aabcccccaaa"; System.out.println(zipString(str)); } public String zipString(String iniString) { // write code here int len = iniString.length(); String str = zip(iniString); int lenzip = str.length(); if(lenzip < len) return str; else return iniString; } public static String zip(String iniString) { // write code here String str = null; if(iniString == null || iniString.length() <= 0) return str; char last = iniString.charAt(0); //记录第一个字符 int length = iniString.length(); StringBuffer buf = new StringBuffer(); buf.append(last); //把第一个字符放进buf int count = 1; //记录重复字符的数量 for(int i=1;i<length;i++){ if(iniString.charAt(i) == last) count++; else{ last = iniString.charAt(i); //修改字符 buf.append(count); //放上一个字符的数量 buf.append(last); //放下一个字符 count = 1; } } buf.append(count); //放最后一个字符的数量 return buf.toString(); } }
面试题1.6:给定一幅有N×N矩阵表示的图像,其中每个像素的大小为4个字节,编写一个方法,将图像旋转90度。不占用额外内存空间能否做到?
package cc150; public class Transform { public static void main(String[] args) { // TODO 自动生成的方法存根 int[][] mat = {{1,2,3},{4,5,6},{7,8,9}}; transformImage(mat, 3); for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ System.out.print(mat[i][j]); } } } public static int[][] transformImage(int[][] mat, int n) { // write code here for(int layer=0;layer<n/2;layer++){ //从最外层开始,总共有n/2层 int first = layer; //确定每一层开始和结束的值 int last = n-1-layer; for(int i=first;i<last;i++){ int offset = i-first; //记录移动的偏移量,循环的时候第一个从左上角开始向下 int top = mat[first][i]; mat[first][i] = mat[last-offset][first]; mat[last-offset][first] = mat[last][last-offset]; mat[last][last-offset] = mat[i][last]; mat[i][last] = top; } } return mat; } }
面试题1.7:编写一个算法,若M×N矩阵中某个元素为0,则将其所在的行与列清零。
注意:一个一个清零会导致最后矩阵中所有的元素都变成零,所以要记录矩阵中所有零元素的位置再清零。并不用建立一个M×N的数组来标记零元素的位置,只用建立两个数组分别来记录每一个零元素的横坐标和纵坐标就行了。
package cc150; public class SetZeros { public static void main(String[] args) { // TODO 自动生成的方法存根 int[][] a = { {1,0,3}, {4,5,6}, }; //原来的数组 for(int i=0;i<a.length;i++){ for(int j=0;j<a[0].length;j++){ System.out.print(a[i][j]+","); } System.out.println(); } //置零 setZeros(a); //现在的数组 for(int i=0;i<a.length;i++){ for(int j=0;j<a[0].length;j++){ System.out.print(a[i][j]+","); } System.out.println(); } } public static void setZeros(int[][] matrix ){ boolean[] row = new boolean[matrix.length]; boolean[] column = new boolean[matrix[0].length]; //记录值为0的元素所在的行和列 for(int i=0;i<matrix.length;i++){//行 for(int j=0;j<matrix[0].length;j++){//列 if(matrix[i][j] == 0){ row[i] = true; column[j] = true; } } } for(int i=0;i<matrix.length;i++){//行 for(int j=0;j<matrix[0].length;j++){//列 if(row[i] || column[j]){ // 其中有一个为true matrix[i][j] = 0; } } } } }
面试题1.8:假定有一个方法isSubstring,可检查一个单词是否为其他字符串的子串。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成,要求只能调用一次isSubstring。(比如,waterbottle是erbottlewat旋转后的字符串。)
思路:令s1为waterbottle,s2为erbottlewat,则s2(erbottlewat)肯定是s1s1(waterbottlewaterbottle)的子串
package cc150; public class ReverseEqual { public static void main(String[] args) { // TODO 自动生成的方法存根 String s1 = "waterbottlea"; String s2 = "erbottlewatb"; System.out.println(checkReverseEqual(s1,s2)); } public static boolean checkReverseEqual(String s1, String s2) { // write code here int len = s1.length(); if(len == s2.length() && len > 0){ String s1s1 = s1 + s1; //return s1s1.indexOf(s2)>0; return s1s1.contains(s2); } return false; } }