面试题17.1:编写一个函数,不用临时变量,直接交换两个数。
思路:使用差值或者异或
package cc150.middle; public class Exchange { public static void main(String[] args) {
// TODO 自动生成的方法存根
int[] a= {1,2};
Exchange ec = new Exchange();
int[] b= ec.exchangeAB(a);
System.out.println(b[0]);
System.out.println(b[1]);
} public int[] exchangeAB(int[] AB) {
// write code here
// AB[0] = AB[0]-AB[1];
// AB[1] = AB[0]+AB[1];
// AB[0] = AB[1]-AB[0]; AB[0] = AB[0]^AB[1];
AB[1] = AB[0]^AB[1];
AB[0] = AB[1]^AB[0];
return AB;
} }
面试题17.2:设计一个算法,判断玩家是否赢了井字游戏。
package cc150.middle; public class Board { //井字棋 public static void main(String[] args) {
// TODO 自动生成的方法存根
int[][] a = {{1,0,1},{1,-1,-1},{1,-1,0}};
Board b = new Board();
System.out.println(b.checkWon(a));
} public boolean checkWon(int[][] board) {
// write code here
int N = board.length;
int row = 0;
int col = 0; //检查行
for(row = 0;row<N;row++){
for(col = 1;col<N;col++){
if(board[row][col] != board[row][col-1])
break;
}
if(col == N && board[row][col-1] == 1)
return true;
} //检查列
for(col = 0;col<N;col++){
for(row = 1;row<N;row++){
if(board[row][col] != board[row-1][col])
break;
}
if(row == N && board[row-1][col] == 1)
return true;
} //检查对角线,从左上角开始
if(board[0][0] != 0){
for(row = 1;row<N;row++){
if(board[row][row] != board[row-1][row-1])
break;
}
if(row == N && board[row-1][row-1] == 1)
return true;
} //检查对角线,左下角开始
if(board[N-1][0] != 0){
for(row = 1;row<N;row++){
if(board[N-row-1][row] != board[N-row][row-1])
break;
}
if(row == N && board[N-row][row-1] == 1)
return true;
}
return false;
} }
面试题17.3:设计一个算法,算出n阶乘有多少个尾随零。
package cc150.middle; public class Factor { public static void main(String[] args) { //n阶乘有多少个尾随零
// TODO 自动生成的方法存根
Factor f = new Factor();
System.out.println(f.getFactorSuffixZero(10));
} public int getFactorSuffixZero(int n) {//统计所有相乘的数中分解出5的个数,2的个数必定大于5,只要统计5的个数即可
// write code here
// int count = 0;
// for(int i=2;i<=n;i++)
// count += factorOf5(i);
// return count; int count = 0;
for(int i=5;n/i>0;i*=5) //如果n=10的话,有2个数在5和25之间
count += n/i;
return count;
} public int factorOf5(int n) {
// write code here
int count = 0;
while(n%5 == 0){ //求余数
count ++;
n/=5;
}
return count;
} }
面试题17.4:编写一个方法,找出两个数字中最大的那一个。不得使用if-else或其他比较运算符。
package cc150.middle; public class Max { public static void main(String[] args) {
// TODO 自动生成的方法存根 } public int getMax(int a, int b) {
// write code here
b = a-b; //此时b>>31为1则b小于0即a<b,若b>>31为0 则a>b
a -= b&(b>>31); //若a<b a=a-(a-b),若a>b a=a-0
return a;
} }
面试题17.6:给定一个整数数组,编写一个函数,找出索引m和n,只要将m和n之间的元素排好序,整个数组就是有序的。注意:n-m越小越好,也就是说,找出符合条件的最短序列。
面试题17.7:给定一个整数,打印该整数的英文描述(例如“One Thousand,Two Hundred Thirty Four”)。
package cc150.middle; public class ToString { public static void main(String[] args) {
// TODO 自动生成的方法存根
ToString ts = new ToString();
System.out.println(ts.toString(1000)); //输入1234,输出"One Thousand,Two Hundred Thirty Four"
} public static String[] digits = {"One","Two","Three","Four","Five","Six","Seven","Eight","Nine"};
public static String[] teens = {"Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"};
public static String[] tens = {"Ten","Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"};
public static String[] bigs = {"","Thousand","Million"}; public String toString(int x) {
// write code here
if(x == 0)
return "Zero";
else if(x < 0)
return "Negative " + toString(-1*x);
int count = 0;
String str = "";
while(x > 0){
if(x % 1000 != 0){
if(count == 0 || str == "") //One Million后面不能有逗号
str = toString100(x % 1000)+bigs[count]+str; //把count大的million放在前面,原来的str放在后面
else
str = toString100(x % 1000)+bigs[count]+","+str; //把count大的million放在前面,原来的str放在后面
}
x /= 1000;
count ++;
}
return str.trim();
} public String toString100(int x){
String str = "";
//转换百位数的地方
if(x >= 100){
str+=digits[x/100-1]+" Hundred ";
x%=100;
}
//转换十位数的地方
if(x >= 11 && x <= 19){
return str+teens[x-11]+" ";
}else if(x == 10 || x >= 20){
str+=tens[x/10-1]+" ";
x%=10;
}
//转换个位数的地方
if(x >= 1 && x<=9){
str+=digits[x-1]+" ";
}
return str;
} }
面试题17.8:给定一个整数数组(有正数有负数),找出总和最大的连续数列,并返回总和。(剑指Offer原题)
package jianzhiOffer; public class FindGreatestSumOfSubArray { //连续子数组的最大和 public static void main(String[] args) {
// TODO 自动生成的方法存根
// int[] Arr = {-1,-2,-3,-10,-4,-7,-2,-5};
int[] Arr = {6,-3,-2,7,-15,1,2,2};
System.out.println(findGreatestSumOfSubArray(Arr));
} public static boolean InvalidInput = false; public static int findGreatestSumOfSubArray(int[] nums){
if(nums == null || nums.length<=0){
InvalidInput = true;
return 0;
}
InvalidInput = true;
int curSum = 0;
int curGreatestSum = Integer.MIN_VALUE;//数组内可能全部都是负数
for(int i=0;i<nums.length;i++){
if(curSum < 0)//如果前n个相加小于0,那么最大的和只能从n+1个开始算
curSum = nums[i];
else
curSum += nums[i];
if(curSum > curGreatestSum)//数组内可能全部都是负数
curGreatestSum = curSum;
}
return curGreatestSum;
} }
面试题17.9:设计一个方法,找出任意指定单词在一本书中的出现频率。
package cc150.middle; import java.util.Hashtable; public class Frequency { public static void main(String[] args) {
// TODO 自动生成的方法存根 } public int getFrequency(String[] article, int n, String word) {
// write code here
return wordFrequency(setupDictionary(article),word);
} public Hashtable<String,Integer> setupDictionary(String[] book){
Hashtable<String,Integer> table = new Hashtable<String,Integer>();
for(String word:book){
word = word.toLowerCase();
if(word.trim() != ""){ //去掉空格之后,不等于空
if(!table.containsKey(word))
table.put(word, 0);
table.put(word, table.get(word)+1);
}
}
return table;
} public int wordFrequency(Hashtable<String,Integer> table, String word){
if(table == null || word == null)
return -1;
word = word.toLowerCase();
if(table.containsKey(word))
return table.get(word);
return 0;
} }
面试题17.12:设计一个算法,找出数组中两数之和为指定值的所有整数对。
package cc150.middle; import java.util.Arrays; public class FindPair { public static void main(String[] args) { //有重复的情况
// TODO 自动生成的方法存根
int[] a = {11,7,7,6,14,2,14,15,2,1,2,12,13,9,8,15,13,8,10,11,14,10,2,9,4,9,3,7,6,10,15,4,7,6,15,3,9,13,5,2,6,10,10,1,12,4,3,3,8,8,1,4,7,11,13,5,13,15,4,3,1,11,6,11,9,9,11,15,12,10,13,3,11,4,8,9,7,3,13,9,11,3,2,11,10,1,4,2,3,3,14,11,5,10,1,14,8,1,11,3,1,9,14,6,1,7,15,10,14,6,4,12,11};
FindPair fp = new FindPair();
System.out.println(fp.countPairs(a,113,16));
} public int countPairs(int[] A, int n, int sum) {
// write code here
Arrays.sort(A);
for(int i=0;i<A.length;i++)
System.out.println(A[i]);
int first = 0;
int end = n-1;
int count=0;
int countLeft = 1;
int countRight = 1;
while(first<end){
int s = A[first]+A[end];
if(s == sum){ //如果相等
if(A[first] == A[end]){ //情况1,一串连续的,且这些相加等于sum
count += ((end-first)*(end-first+1)/2);
return count; //注意要在这里结束,否则会继续计数
}else{ //情况2,两串连续的,两个串中各取一个相加等于sum
while(A[first] == A[first+1]){
countLeft++;
first++;
}
while(A[end] == A[end-1]){
countRight++;
end--;
}
count += (countLeft*countRight);
}
first++;
end--;
countLeft=1; //注意开始计数是1
countRight=1;
}else{
if(s>sum)
end--;
else
first++;
}
}
return count;
} }
面试题17.13:有个简单的类似结点的数据结构BiNode,包含两个指向其他结点的指针。数据结构BiNode可用来表示二叉树(其中node1为左子节点,node2为右子节点)或双向链表(其中node1为前趋结点,node2为后继结点)。编写一个方法,将二叉查找树(用BiNode实现)转换为双向链表。要求所有数值的排序不变,转换操作不得引入其他数据结构(即直接操作原先的数据结构)。
package cc150.middle; public class Converter { public static void main(String[] args) { //二叉查找树转换成双向链表
// TODO 自动生成的方法存根
Converter cv = new Converter();
TreeNode t4 = cv.new TreeNode(4);
TreeNode t2 = cv.new TreeNode(2);
TreeNode t5 = cv.new TreeNode(5);
TreeNode t1 = cv.new TreeNode(1);
TreeNode t3 = cv.new TreeNode(3);
TreeNode t6 = cv.new TreeNode(6);
TreeNode t0 = cv.new TreeNode(0);
t4.left = t2;
t4.right = t5;
t2.left = t1;
t2.right = t3;
t5.right = t6;
t1.left = t0;
cv.treeToList(t4);
while(cv.head.next != null){
System.out.println(cv.head.val);
cv.head = cv.head.next;
} } private ListNode head = new ListNode(-1);
private ListNode q = head; public ListNode treeToList(TreeNode root) { //使用中序遍历
// write code here
if(root != null){
treeToList(root.left);
q.next = new ListNode(root.val);
q = q.next;
treeToList(root.right);
}
return head.next; } public class ListNode {
int val;
ListNode next = null; ListNode(int val) {
this.val = val;
}
} public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
} }