面试题34:二叉树中和为某一值的路径
import java.util.Stack;
public class test34 {
public static Stack path = new Stack<>();
public static class Node{
int item;
Node left, right;
public Node(int item){
this.item = item;
}
}
public static void findPath(Node h, int target, int weight){
if (h == null || weight > target) return;
path.push(h);
weight += h.item;
if (weight == target && h.left == null && h.right == null) {
for (Node x: path){
System.out.printf("%d ", x.item);
}
System.out.println();
path.pop();
}
else if (weight < target){
findPath(h.left,target,weight);
findPath(h.right,target,weight);
path.pop();
}
}
public static void main(String[] args){
Node root = new Node(10);
root.left = new Node(5);
root.right = new Node(12);
root.left.left = new Node(4);
root.left.right = new Node(7);
findPath(root,22,0);
}
}
面试题35:复杂链表的复制
public class test35 {
public class Node{
int val;
Node next, random;
}
public static Node clone(Node h) {
if (h == null) return null;
Node current = h;
while (current != null) {
Node temp = new Node(current.item);
temp.next = current.next;
current.next = temp;
current = temp.next;
}
current = h;
while (current != null) {
Node temp = current.next;
if (current.random != null) {
temp.random = current.random.next;
}
current = temp.next;
}
current = h;
Node cloneHead = current.next;
Node clonecurrent = current.next;
while (current != null) {
current.next = clonecurrent.next;
clonecurrent.next = current.next.next;
current = current.next;
clonecurrent = clonecurrent.next;
}
return cloneHead;
}
}
面试题36:二叉搜索树与双向链表
public class test36 {
private static Node root;
private static class Node{
int item;
Node left, right;
public Node(int item){
this.item = item;
}
}
public static Node convert(Node h){
if (h == null) return null;
Node last = null;
last = convert(h, last);
Node head = last;
while (head.left != null)
head = head.left;
return head;
}
public static Node convert(Node root, Node last) {
if (root == null) return last;
last = convert(root.left, last);
if (last != null) {
last.right = root;
root.left = last;
}
last = root;
last = convert(root.right, last);
return last;
}
}
面试题37:序列化二叉树
import java.util.LinkedList;
import java.util.Queue;
public class test37 {
public static class TreeNode{
int val;
TreeNode left, right;
public TreeNode(int val){
this.val = val;
}
}
public static String Serialize(TreeNode h){
if (h == null) return null;
StringBuilder str = new StringBuilder();
Serialize(h, str);
return str.toString();
}
public static void Serialize(TreeNode h, StringBuilder str){
if (h == null){
str.append("#,");
return;
}
str.append(h.val + ",");
Serialize(h.left, str);
Serialize(h.right, str);
}
public static void Deserialize(String str){
if (str == null) return;
String[] string = str.split(",");
Queue queue = new LinkedList<>();
for (int i = 0; i < string.length; i++){
queue.add(string[i]);
}
Deserialize(queue);
}
public static TreeNode Deserialize(Queue queue){
if (queue.isEmpty()) return null;
String s = queue.poll();
if (s.equals("#")) return null;
TreeNode root = new TreeNode(Integer.valueOf(s));
root.left = Deserialize(queue);
root.right = Deserialize(queue);
return root;
}
}
面试题38:字符串的排列
类似的字符串排列参见面试题17的方案2
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class test38 {
public ArrayList Permutation(String str){
if (str == null) return null;
List list = new ArrayList<>();
char[] s = str.toCharArray();
resolve(s, 0, list);
Set set = new TreeSet<>(list);
list = new ArrayList<>(set);
return (ArrayList) list;
}
private void resolve(char[] str, int index, List list){
if (index == str.length-1){
list.add(String.valueOf(str));
return;
}
for (int i = index; i < str.length; i++){
char temp = str[index];
str[index] = str[i];
str[i] = temp;
resolve(str, index+1, list);
temp = str[index];
str[index] = str[i];
str[i] = temp;
}
}
public static void main(String[] args){
String str = new String("abc");
for (String s: new Solution().Permutation(str))
System.out.println(s);
}
}
还有一种解法,用到了队列和栈
public class test38 {
public static void main(String[] args) {
String input = "abc";
Queue queue = new LinkedList<>();
for (int i = 0; i < input.length(); i++) {
queue.add(input.charAt(i));
}
permutation(queue, new Stack<>());
}
public static void permutation(Queue queue, Stack stack) {
if (queue.isEmpty()) {
System.out.println(stack);
}
for (int i = 0; i < queue.size(); i++) {
char element = queue.poll();
stack.push(element);
permutation(queue, stack);
queue.add(element);
stack.pop();
}
}
}
扩展问题:求字符的所有组合
public class test38 {
public static void main(String[] args) {
String input = "abc";
for (int j = 1; j <= input.length(); j++) {
Queue queue = new LinkedList<>();
for (int i = 0; i < input.length(); i++) {
queue.add(input.charAt(i));
}
permutation2(j, queue, new Stack<>());
}
}
public static void permutation2(int N, Queue queue, Stack stack) {
if (N == 0) {
System.out.println(stack);
return;
}
if (queue.isEmpty()) {
return;
}
char element = queue.poll();
stack.push(element);
permutation2(N-1, queue, stack);
stack.pop();
permutation2(N, queue, stack);
}
}
面试题39:数组中出现次数超过一半的数字
public class test39 {
public static void main(String[] args){
int[] a = new int[]{1,2,3,2,2,2,5,4,2};
resolve(a);
}
public static void resolve(int[] a){
int count = 1;
int number = a[0];
for (int i = 1; i < a.length; i++){
if (a[i] == number) {
count++;
}
else {
count--;
if (count == 0){
number = a[i];
count = 1;
}
}
}
if (!CheckMoreThanHalf(a, number)) {
System.out.println("null");
return;
}
System.out.println(number);
}
public static boolean CheckMoreThanHalf(int[] a, int number){
int count = 0;
for (int i = 0; i < a.length; i++){
if (a[i] == number)
count++;
if (count*2>=a.length)
return true;
}
return false;
}
}
面试题40:最小的k个数
方案1:基于快速排序的partition方法,时间复杂度为O(n)
public class test40 {
public static void main(String[] args){
int[] a = new int[]{4,5,1,6,2,7,3,8};
int n = 4;
int start = 0, end = a.length-1;
int index = partition(a, start, end);
while (index != n){
if (index < n){
end = index - 1;
index = partition(a, start, end);
}
else {
start = index + 1;
index = partition(a, start, end);
}
}
}
public static int partition(int[] a, int lo, int hi){
int v = a[lo];
int i = lo, j = hi+1;
while (true){
while (a[++i] < v){
if (i == hi) break;
}
while (v < a[--j]){
if (j == lo) break;
}
if (i >= j) break;
exch(a, i, j);
}
exch(a, lo, j);
return j;
}
public static void exch(int[] a, int i, int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
方案2:基于红黑树或优先队列,适合于海量数据,时间复杂度为O(nlogk)
import java.util.ArrayList;
import java.util.Collections;
import java.util.PriorityQueue;
import java.util.Queue;
public class test40 {
public static ArrayList main(String[] args){
int[] a = new int[]{4,5,1,6,2,7,3,8};
int n = 4;
return resolve(a, 4);
}
public static ArrayList resolve(int[] a, int k){
ArrayList list = new ArrayList<>();
if (a == null || k <= 0 || k > a.length) return null;
Queue queue = new PriorityQueue<>(k, Collections.reverseOrder());
for (int i = 0; i < a.length; i++){
if (queue.size() < k){
queue.add(a[i]);
}
else {
if (a[i] < queue.peek()){
queue.remove();
queue.add(a[i]);
}
}
}
for (int i: queue){
list.add(i);
}
return list;
}
}
面试题41:数据流中的中位数
public class Solution {
BST tree = new BST();
static final boolean RED = true, BLACK = false;
public void Insert(Integer num) {
tree.put(num);
}
public Double GetMedian() {
return tree.getmid();
}
public class BST{
private Node root;
private class Node{
int val;
Node left, right;
int N;
boolean color;
public Node(int val, int N, boolean color){
this.val = val;
this.N = N;
this.color = color;
}
}
public boolean isEmpty(){return root == null;}
public boolean isRED(Node h){
if (h == null) return false;
return h.color == RED;
}
public int size(Node h){
if (h == null) return 0;
return h.N;
}
public double getmid(){
if (root == null) return 0.0;
int l = size(root.left);
int r = size(root.right);
int mid = (l+r+1)/2;
if ((l+r+1)%2!=0) return (double) select(mid);
else return (double) (select(mid-1)+select(mid))/2;
}
public int select(int k){
return select(root, k);
}
public int select(Node h, int k){
if (h == null) return 0;
int t = size(h.left);
if (t > k) return select(h.left, k);
else if (t == k) return h.val;
else {
return select(h.right, k-t-1);
}
}
public Node rotateLeft(Node h){
Node x = h.right;
h.right = x.left;
x.left = h;
x.N = h.N;
x.color = h.color;
h.N = size(h.left) + size(h.right) + 1;
h.color = RED;
return x;
}
public Node rotateRight(Node h){
Node x = h.left;
h.left = x.right;
x.right = h;
x.N = h.N;
x.color = h.color;
h.N = size(h.left) + size(h.right) + 1;
h.color = RED;
return x;
}
public void flipColors(Node h){
h.color = !h.color;
h.left.color = !h.left.color;
h.right.color = !h.right.color;
}
public void put(int val){
root = put(root, val);
root.color = BLACK;
}
private Node put(Node h, int val){
if (h == null) return new Node(val, 1, RED);
if (val < h.val) h.left = put(h.left, val);
else if (val == h.val) h.val = val;
else h.right = put(h.right, val);
if (!isRED(h.left) && isRED(h.right)) h = rotateLeft(h);
if (isRED(h.left) && isRED(h.left.left)) h = rotateRight(h);
if (isRED(h.left) && isRED(h.right)) flipColors(h);
h.N = size(h.left) + size(h.right) + 1;
return h;
}
}
}
面试题42:连续子数组的最大和
方案1:举例分析数组规律
public class test42 {
public static void main(String[] args){
int[] a = new int[]{1,-2,3,10,-4,7,2,-5};
resolve(a);
}
public static void resolve(int[] a){
if (a == null){
System.out.println(0);
return;
}
int maxsum = a[0];
int sum = a[0];
for (int i = 1; i < a.length; i++){
if (sum <= 0){
sum = a[i];
}
else {
sum += a[i];
}
if (sum > maxsum){
maxsum = sum;
}
}
System.out.println(maxsum);
}
}
方案2:动态规划
public class test42 {
public static void main(String[] args){
int[] a = new int[]{1,-2,3,10,-4,7,2,-5};
resolve(a);
}
public static void resolve(int[] a){
if (a == null) return;
int[] dp = new int[a.length];
for (int i = 0; i < a.length; i++){
if (i == 0 || dp[i-1] < 0) dp[i] = a[i];
else dp[i] = dp[i-1] + a[i];
}
int max = dp[0];
for (int i = 1; i < a.length; i++){
if (dp[i] > max)
max = dp[i];
}
System.out.println(max);
}
}
面试题43:1~n整数中1出现的次数
public class test43 {
public static void main(String[] args){
System.out.println(NumberOf1Between1AndN_Solution(12));
}
public static int NumberOf1Between1AndN_Solution(int n) {
int ones = 0;
for (int m = 1; m <= n; m*=10){
int a = n/m, b = n%m;
if (a%10==0) ones += a/10 * m;
else if (a%10==1) ones += (a/10*m) + (b+1);
else ones += (a/10+1)*m;
}
return ones;
}
}
面试题44:数字序列中某一位的数字
面试题45:把数组排成最小的数
面试题46:把数字翻译成字符串
面试题47:礼物的最大价值(动态规划)
public class test47 {
public static void main(String[] args){
int[][] a = new int[][]{{1,10,3,8},{12,2,9,6},{5,7,4,11},{3,7,16,5}};
resolve(a);
}
public static void resolve(int[][] a){
if (a == null) return;
int row = a.length, col = a[0].length;
for (int i = row - 2; i >= 0; i--){
a[i][col-1] += a[i+1][col-1];
}
for (int j = col - 2; j >= 0; j--){
a[row-1][j] += a[row-1][j+1];
}
for (int i = row-2; i >= 0; i--){
for (int j = col-2; j >= 0; j--){
a[i][j] += Integer.max(a[i+1][j], a[i][j+1]);
}
}
System.out.println(a[0][0]);
}
}
面试题48:最长不含重复字符的子字符串(动态规划)
public class test48 {
public static void main(String[] args){
String str = new String("arabcacfr");
resolve(str);
}
public static void resolve(String str){
if (s == null) {
return -1;
}
int[] positionIndex = new int[26];
for (int i = 0; i < 26; i++) {
positionIndex[i] = -1;
}
int[] dp = new int[s.length()];
dp[0] = 1;
positionIndex[s.charAt(0) - 'a'] = 0;
for (int i = 1; i < s.length(); i++) {
int dist = i - positionIndex[s.charAt(i) - 'a'];
if (positionIndex[s.charAt(i) - 'a'] == -1 || dist > dp[i-1]) {
dp[i] = dp[i-1] + 1;
} else if (dist == dp[i-1]){
dp[i] = dp[i-1];
} else {
dp[i] = dist;
}
positionIndex[s.charAt(i) - 'a'] = i;
}
int max = dp[0];
for (int i = 1; i < s.length(); i++) {
if (dp[i] > max) {
max = dp[i];
}
}
return max;
}
}
面试题49:丑数
public class test49 {
public static void main(String[] args){
int n = 1500;
resolve(n);
}
public static void resolve(int n){
if (n <= 0) return;
int[] a = new int[n];
a[0] = 1;
int t2 = 0, t3 = 0, t5 = 0;
for (int i = 1; i < n; i++){
a[i] = Integer.min(a[t2]*2, Integer.min(a[t3]*3, a[t5]*5));
if (a[i] == a[t2]*2) t2++;
if (a[i] == a[t3]*3) t3++;
if (a[i] == a[t5]*5) t5++;
}
System.out.println(a[n-1]);
}
}
面试题50:第一次只出现一次的字符
无论是字符串还是字符流中第一次只出现一次的字符,解决办法都基于哈希表,时间复杂度为O(n),空间复杂度为O(1)
import java.util.LinkedHashMap;
public class test50 {
public static void main(String[] args){
String str = new String("abaccdeff");
resolve(str);
}
public static void resolve(String str){
if (str == null) return;
char[] s = str.toCharArray();
LinkedHashMap hash = new LinkedHashMap<>();
for (int i = 0; i < s.length; i++){
if (hash.containsKey(s[i])){
hash.put(s[i], hash.get(s[i])+1);
}
else hash.put(s[i], 1);
}
for (char key: hash.keySet()){
if (hash.get(key) == 1){
System.out.println(key);
return;
}
}
}
}
面试题51:数组中的逆序对
自底向上的归并排序中的子问题
public class test51 {
public static class Merge{
int count = 0;
public int[] aux;
public void sort(int[] a){
if (a == null) return;
aux = new int[a.length];
sort(a, 0, a.length-1);
}
private void sort(int[] a, int lo, int hi){
if (lo >= hi) return;
int mid = lo+(hi-lo)/2;
sort(a,lo,mid);
sort(a,mid+1,hi);
merge(a, lo, mid, hi);
}
private void merge(int[] a, int lo, int mid, int hi){
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++){
aux[k] = a[k];
}
for (int k = lo; k <= hi; k++){
if (i == mid+1) a[k] = aux[j++];
else if (j == hi+1) a[k] = aux[i++];
else if (aux[i] > aux[j]) {
count+=(j-k);
a[k] = aux[j++];
}
else {
a[k] = aux[i++];
}
}
}
}
public static void main(String[] args){
int[] a = new int[]{7,5,6,4};
Merge merge = new Merge();
merge.sort(a);
System.out.println(merge.count);
}
}
面试题52:两个链表的第一个公共节点
public class test52 {
public static class Node{
int key;
Node next;
}
public static void main(String[] args){
Node node1 = new Node();
Node node2 = new Node();
Node same = resolve(node1, node2);
}
public static Node resolve(Node node1, Node node2){
if (node1 == null || node2 == null) return null;
Node current = node1;
int length1 = 1, length2 = 1;
while (current.next != null){
length1++;
current = current.next;
}
current = node2;
while (current.next != null){
length2++;
current = current.next;
}
for (int i = 0; i < Math.abs(length1-length2); i++){
if (length1 > length2){
node1 = node1.next;
}
else if (length2 > length1){
node2 = node2.next;
}
}
while (node1.next != null && node2.next != null && node1 != node2){
node1 = node1.next;
node2 = node2.next;
}
return node1;
}
}
面试题53:在排序数组中查找数字
题目一:数字在排序数组中出现的次数
public class test53 {
public static void main(String[] args){
int[] a = new int[]{1};
int target = 3;
System.out.println(resolve(a, target));
}
public static int resolve(int[] a, int n){
if (a == null) return -1;
int first = getFirst(a, n, 0, a.length-1);
int last = getLast(a, n, 0, a.length-1);
if (first <= last && first >= 0 && last >= 0) return last - first + 1;
else return -1;
}
public static int getFirst(int[] a, int target, int start, int end){
while (start <= end){
int mid = start + (end - start)/2;
if (a[mid] > target){
end = mid-1;
continue;
}
else if (a[mid] < target){
start = mid+1;
continue;
}
else {
if (a[mid-1] == target){
end = mid-1;
continue;
}
else return mid;
}
}
return -1;
}
public static int getLast(int[] a, int target, int start, int end){
while (start <= end && start>=0 && end>=0){
int mid = start + (end - start)/2;
if (a[mid] > target){
end = mid+1;
continue;
}
else if (a[mid] < target){
start = mid-1;
continue;
}
else {
if (a[mid+1] == target){
start = mid+1;
continue;
}
else return mid;
}
}
return -1;
}
}
题目二:0~n-1中缺失的数字
public class test53 {
public static void main(String[] args){
int[] a = new int[]{};
System.out.println(resolve(a));
}
public static int resolve(int[] a){
if (a == null) return -1;
int start = 0, end = a.length-1;
while (start <= end){
int mid = start + (end-start)/2;
if (a[mid] == mid){
start = mid+1;
continue;
}
else if (a[mid] > mid){
if (a[mid-1] == mid-1) return mid;
end = mid-1;
continue;
}
}
return -1;
}
}
面试题54:二叉搜索树的第k大节点
public class test54 {
public static class Node{
int val;
Node left, right;
}
public static void main(String[] args){
Node root = new Node();
int k = 4;
resolve(root, k);
}
public static void resolve(Node h, int k){
if (h == null) return;
resolve(h.left, k);
if (--k == 0) System.out.println(h.val);
resolve(h.right, k);
}
}
面试题55:二叉树的深度
题目一:二叉树的深度
public class test55 {
public static class Node{
int val;
Node left, right;
}
public static void main(String[] args){
Node root = new Node();
System.out.println(depth(root));
}
public static int depth(Node h){
if (h == null) return 0;
int l = depth(h.left);
int r = depth(h.right);
return l>r?(l+1):(r+1);
}
}
题目二:平衡二叉树
public class test55 {
public static boolean isbalance = true;
public static class Node{
int val;
Node left, right;
}
public static void main(String[] args){
Node root = new Node();
if (root == null) {
System.out.println("false");
return;
}
System.out.println(isBalanced(root, 0));
}
public static int isBalanced(Node h, int depth){
if (h == null) {
return 0;
}
int l = isBalanced(h.left, depth);
int r = isBalanced(h.left, depth);
if (Math.abs(l-r) > 1){
isbalance = false;
}
return l>r?(l+1):(r+1);
}
}
面试题56:数组中数字出现的次数
题目一:数组中只出现一次的两个数字
public class test56 {
public static void main(String[] args){
int[] a = new int[]{2,4,3,6,3,2,5,5};
resolve(a);
}
public static void resolve(int[] a){
if (a==null) return;
int result = 0;
for (int i = 0; i < a.length; i++){
result ^= a[i];
}
int index = find(result);
int num1 = 0, num2 = 0;
for (int i = 0; i < a.length; i++){
if (isbit(a[i], index)) num1 ^= a[i];
else num2 ^= a[i];
}
System.out.printf("%d, %d", num1, num2);
}
public static int find(int num){
int index = 0;
while ((num&1)==0 && index < 32){
num=num>>1;
index++;
}
return index;
}
public static boolean isbit(int num, int index){
num = num >> index;
return (num&1) == 0;
}
}
题目二:数组中唯一只出现一次的数字
public class test56 {
public static void main(String[] args){
int[] a = new int[]{2,4,4,4,3,3,3,5,5,5};
resolve(a);
}
public static void resolve(int[] a) {
if (a == null) return;
int[] result = new int[32];
for (int i = 0; i < a.length; i++){
int bit = 1;
for (int j = 31; j >= 0; j--){
if ((a[i]&bit) != 0){
result[j]+=1;
}
bit=bit<<1;
}
}
int num = 0;
for (int i = 0; i < result.length; i++){
if (result[i] % 3 != 0){
num++;
num=num<<1;
}
}
System.out.println(num);
}
}
面试题57:和为s的数字
题目一:和为s的两个数字
public class test57 {
public static void main(String[] args){
int[] a = new int[]{1,2,4,7,11,15};
int n = 15;
resolve(a, n);
}
public static void resolve(int[] a, int n){
if (a == null || a[0]+a[a.length-1] < n || a[0] > n) return;
int lo = 0, hi = a.length-1;
while (lo < hi){
if (a[lo] + a[hi] == n){
System.out.printf("%d, %d", a[lo], a[hi]);
return;
}
else if (a[lo] + a[hi] < n){
lo++;
continue;
}
else {
hi--;
continue;
}
}
return;
}
}
题目二:和为s的连续正数序列
public class test57 {
public static void main(String[] args){
int n = 15;
resolve(n);
}
public static void resolve(int n){
if (n<=2) return;
int lo = 1, hi = 2;
while (lo < hi && hi < n){
if (sum(lo, hi) == n){
System.out.printf("%d~%d\n", lo, hi);
hi++;
}
else if (sum(lo, hi) < n){
hi++;
continue;
}
else {
lo++;
continue;
}
}
return;
}
public static double sum(int lo, int hi){
int count = hi - lo + 1;
return (lo+hi)*count/2;
}
}
面试题58:翻转字符串
题目一:翻转单词顺序
public class test58 {
public static void main(String[] args){
String s = new String("I am a student.");
resolve(s);
}
public static void resolve(String s){
if (s == null) return;
String[] str = s.split(" ");
for (int i = str.length-1; i >= 0; i--){
System.out.print(str[i]);
System.out.print(" ");
}
}
}
题目二:左旋转字符串
public class test58 {
public static void main(String[] args){
String s = new String("abcdefg");
int n = 2;
resolve(s, n);
}
public static void resolve(String s, int n){
if (s == null || n < 0 || n > s.length()) return;
char[] string = s.toCharArray();
Reverse(string, 0, n-1);
Reverse(string, n, string.length-1);
Reverse(string, 0, string.length-1);
System.out.print(String.valueOf(string));
}
public static void Reverse(char[] string, int lo, int hi){
while (lo < hi){
char temp = string[lo];
string[lo] = string[hi];
string[hi] = temp;
lo++;
hi--;
}
}
}
面试题63:股票的最大利润
public class test63 {
public static void main(String[] args) {
int[] input = new int[]{9, 11, 8, 5, 7, 12, 16, 14};
int max = getMaxDiff(input);
System.out.println(max);
}
public static int getMaxDiff(int[] input) {
if (input == null || input.length <= 1) {
return -1;
}
int min = input[0];
int maxDiff = -1;
for (int i = 1; i < input.length; i++) {
if (input[i] - min > maxDiff) {
maxDiff = input[i] - min;
}
if (input[i] < min) {
min = input[i];
}
}
return maxDiff;
}
}