基础类:
public class CQueue {
private Stack<Object> stack1;
private Stack<Object> stack2;
}
链表
public class ListNode {
public Object value=null;
public ListNode next=null;
}
树:
public class TreeNode {
public int sign = 0;
public Object val;
public TreeNode left;
public TreeNode right;
public ArrayList<TreeNode> nodes = new ArrayList<>();
public TreeNode root;
public TreeNode parent;
}
/*面试题12*/
public static boolean hasPath(char[][] matrix, String str) {
if (matrix.length < 1 || matrix[0].length < 1 || str.isEmpty())
return false;
int rows = matrix.length;
int cols = matrix[0].length;
boolean[] visited = new boolean[rows * cols]; //已经初始化为false了
int pathLength = 0;
//从左上角点开始
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (hasPathCore(matrix, row, rows, col, cols, pathLength, visited, str))
return true;
}
}
return false;
}
private static boolean hasPathCore(char[][] matrix, int row, int rows, int col, int cols, int pathLength, boolean[] visited, String str) {
//路径字符串上所有的字符都在矩阵中找到合适的位置,则结束。
if (pathLength == str.length())
return true;
boolean hasPath = false;
if (row >= 0 && row < rows && col >= 0 && col < cols && matrix[row][col] == (str.charAt(pathLength)) && !visited[row * cols + col]) {
++pathLength;
visited[row * cols + col] = true;
/*上下左右*/
hasPath = hasPathCore(matrix, row, rows, col - 1, cols, pathLength, visited, str) ||
hasPathCore(matrix, row, rows, col + 1, cols, pathLength, visited, str) ||
hasPathCore(matrix, row - 1, rows, col, cols, pathLength, visited, str) ||
hasPathCore(matrix, row + 1, rows, col, cols, pathLength, visited, str);
/*如果上下左右都没有匹配到相同的,回到前一个字符(pathLength-1)*/
if (!hasPath) {
--pathLength;
visited[row * cols + col] = false;
}
}
return hasPath;
}
/*面试题13*/
public static int movingCount(int cols, int rows, int threshold) {
if (cols < 1 && rows < 1 && threshold < 0)
return 0;
boolean[] visited = new boolean[cols * rows];
int count;
count = movingCountCore(0, rows, 0, cols, threshold, visited);//从(0,0)开始移动
return count;
}
private static int movingCountCore(int row, int rows, int col, int cols, int threshold, boolean[] visited) {
int count = 0;
/*从坐标点来判断是不是能进入(row, col)这个格子*/
if (row >= 0 && row < rows && col >= 0 && col < cols && getDigitSum(col, row) <= threshold && !visited[row * cols + col]) {
visited[row * cols + col] = true;
/*然后进入下一个格子,将结果相加,用1加上下一步的结果。*/
count = 1 + movingCountCore(row + 1, rows, col, cols, threshold, visited) +
movingCountCore(row - 1, rows, col, cols, threshold, visited) +
movingCountCore(row, rows, col + 1, cols, threshold, visited) +
movingCountCore(row, rows, col - 1, cols, threshold, visited);
}
return count;
}
private static int getDigitSum(int x, int y) {
int sum = 0;
while (x > 0 && y > 0) {
sum += x % 10;
sum += y % 10;
x = x / 10;
y = y / 10;
}
return sum;
}
/*面试题14,动态规划,剪绳子*/
public static int maxProductAfterCutting_solution1(int length) {
if (length < 2)
return 0;
if (length == 2)
return 1;
if (length == 3)
return 2;
int[] products = new int[length + 1];
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3;
int max;
for (int i = 4; i <= length; i++) {
max = 0;
for (int j = 1; j <= i / 2; j++) {
int product = products[j] * products[i - j];
if (max < product)
max = product;
}
products[i] = max;
}
max = products[length];
return max;
}
/*面试题15
* NumbeOf1没有考虑负数情况。
* */
public static int NumberOf1(int n) {
int count = 0;
while (n > 0) {
if ((n & 1 ) != 0) //与1与操作,如果等于1,则最右边一位是1.
count++;
n = n >> 1;//整数右移一位
}
return count;
}
/*因为负数的右移要在末尾添加1,这样会导致死循环,所以干脆左移
* 从1开始,一次左移一位,然后与n做与运算。
* 这种解法循环的次数等于整数二进制的位数,32位整数需要循环32次。
* */
public static int NumberOf2(int n){
int count = 0;
int flag = 1;
while (flag != 0){
if ((n & flag) != 0)
count++;
flag = flag << 1;
}
return count;
}
/*一个整数减去1的结果与原整数做与运算,会把该整数最右边的1变成0.
* 基于这个,一个整数有多少个1,就可以做多少次这种操作!*/
public static int NumberOf3(int n){
int count = 0;
while (n>0){
count++;
n = n & (n - 1);
}
return count;
}
/*判断一个整数是不是2的整数次方,(一个整数减去1的结果与原整数做与运算,会把改整数最右边的1变为0),
* 如果一个数是2的整数次方,则这个整数的二进制中只有一个1,则只可以做一次这种运算!
* */
public static boolean is2IntPower(int n){
int count = 0;
while (n>0){
if (count>1) {
break;
}
count++;
n = n & (n - 1);
}
return count <= 1;
}
/*面试题16,求c中的power(base,exponent)求base的exponent次方函数java实现,
* 需要考虑的问题:
* 1.边界,base=0无意义
* 2.exponent是正数和负数的处理不同,(负数时先求exponent的绝对值次方然后求倒数).
*
* */
private static double Power(double base, int exponent) throws Exception {
if (base == 0)
throw new Exception("error input!");
// if (base == 1 || exponent==0)
// return 1;
double result;
int absExponent = exponent;
if (exponent < 0)
absExponent = -exponent;
result = PowerWithUnsignedExponent1(base, absExponent);
if (exponent < 0)
return 1.0 / result;
else
return result;
}
private static double PowerWithUnsignedExponent1(double base, int exponent) {
double result = 1.0;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
/*如果exponent是32,需要循环32次,可以用递归优化之,并用位运算来代替‘/’,‘%’运算*/
private static double PowerWithUnsignedExponent2(double base, int exponent) {
if (exponent == 0)
return 1;
if (exponent == 1)
return base;
// “ a/2 ==> a>>1 ”
double result = PowerWithUnsignedExponent2(base, exponent >> 1);
result *= result;
// “ a%2 == 1(奇数) ==> a&1 == 1(奇数) ”
if ((exponent & 1) == 1) //如果n为奇数,还需要另外乘以一个base
result *= base;
return result;
}
/*面试题20*/
static int s = 0;
private static boolean isNumeric(String string) {
if (string.isEmpty())
return false;
char[] str = string.toCharArray();
boolean numeric = scanInteger(str);
if (s < str.length && str[s] == '.') {
s++;
numeric = scanUnsignedInteger(str) || numeric;
}
if (s < str.length && (str[s] == 'e' || str[s] == 'E')) {
s++;
numeric = numeric && scanInteger(str);
}
return numeric && (s == str.length);
}
private static boolean scanInteger(char[] str) {
if (str[s] == '+' || str[s] == '-')
s++;
return scanUnsignedInteger(str);
}
private static boolean scanUnsignedInteger(char[] str) {
int numEnd = s;
while (s < str.length && str[s] >= '0' && str[s] <= '9')
s++;
return numEnd < s;
}
/*面试题21,调整整数数组,奇数在前,偶数在后*/
private static int[] reorderOddEven(int[] nums) throws Exception {
if (nums.length == 0)
throw new Exception("null arrays");
int head = 0, tail = nums.length - 1;
int temp;
while (head <= tail) {
if (((nums[head] & 1) == 1) && ((nums[tail] & 1) == 1)) { //都为奇数
head++;
} else if (((nums[head] & 1) == 0) && ((nums[tail] & 1) == 0)) {
tail--;
} else if (((nums[head] & 1) == 0) && ((nums[tail] & 1) == 1)) {
temp = nums[head];
nums[head] = nums[tail];
nums[tail] = temp;
head++;
tail--;
} else {
head++;
tail--;
}
}
return nums;
}
/*面试提22, 链表中倒数地k个节点,
* 两个指针,头指针先走到k-1个节点,然后尾指针开始一起走,当头指针走到链表结尾,此时尾指针所在的节点就是倒数第k个
* */
private static ListNode findKthToTail(ListNode head, int k) {
if (head==null||k==0)
return null;
ListNode pHead = head;
ListNode pBehind = head;
for (int i=0;i<k-1;i++){
if (pHead.next!=null)
pHead = pHead.next;
else
return null;
}
while (pHead.next!=null){
pHead = pHead.next;
pBehind = pBehind.next;
}
return pBehind;
}
/*面试题23,链表中环的入口节点*/
private static ListNode meetingNode(ListNode head){
if (head == null)
return null;
ListNode p1 = head.next;
if (p1 == null)
return null;
ListNode p2 = p1.next;
while (p2 != null && p1!=null){
if (p2 == p1){
return p2;
}
p1 = p1.next;
p2 = p2.next;
if (p2 != null)
p2 = p2.next;
}
return null;
}
private static ListNode entryNodeOfFloop(ListNode head) {
ListNode nodeInLoop = meetingNode(head);
if (nodeInLoop == null)
return null;
//获得环中节点个数
int loopNodes_count = 1;
ListNode temp = nodeInLoop;
while (temp.next != nodeInLoop){
temp = temp.next;
loopNodes_count++;
}
//环入口节点
ListNode p1 = head;
ListNode p2 = head;
for (int i=0;i<loopNodes_count;i++)
p1 = p1.next;
while (p1 != p2){
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
/*面试题24,反转链表*/
private static ListNode reverseList(ListNode head) {
if (head == null)
return null;
ListNode p1 = head;
ListNode p2 = null;
ListNode reversedHead = null;
while (p1 != null) {
ListNode p1Next = p1.next;
//当p1Next为空,说明到结尾了,把头指针赋值给reversedHead,用于返回
if (p1Next == null)
reversedHead = p1;
p1.next = p2;
p2 = p1;
p1 = p1Next;
}
return reversedHead;
}
/*面试题25,合并两个递增链表*/
private static ListNode Merge(ListNode pHead1, ListNode pHead2) {
if (pHead1 == null)
return pHead2;
if (pHead2 == null)
return pHead1;
ListNode pMergeHead;
if ((int) pHead1.value < (int) pHead2.value) {
pMergeHead = pHead1;
pMergeHead.next = Merge(pHead1.next, pHead2);
} else {
pMergeHead = pHead2;
pMergeHead.next = Merge(pHead1, pHead2.next);
}
return pMergeHead;
}
/*面试题26, 数的子结构*/
private static boolean hasSubTree(TreeNode t1, TreeNode t2) {
boolean result = false;
//如果t1,t2有一个为null,则返回为false;
if (t1 != null && t2 != null) {
if (t1.val == t2.val){
result = DoesTree1HasTree2(t1, t2);
}
if (!result)
result = hasSubTree(t1.left, t2);
if (!result)
result = hasSubTree(t1.right, t2);
}
return result;
}
private static boolean DoesTree1HasTree2(TreeNode tree1, TreeNode tree2){
boolean ISHAVE = false;
if (tree2 == null)
return true;
if (tree1 == null)
return false;
if (tree1.val == tree2.val)
ISHAVE = true;
ISHAVE = ISHAVE&DoesTree1HasTree2(tree1.left, tree2.left);
ISHAVE = ISHAVE&DoesTree1HasTree2(tree1.right, tree2.right);
return ISHAVE;
}
//书上版本
private static boolean DoesTree1HasTree2_1(TreeNode tree1, TreeNode tree2){
if (tree2 == null)
return true;
if (tree1 == null)
return false;
if (tree1.val != tree2.val)
return false;
return DoesTree1HasTree2_1(tree1.left, tree2.left) && DoesTree1HasTree2_1(tree1.right, tree1.right);
}
/*面试题27, 二叉树的镜像*/
//1.层次遍历实现
private static TreeNode Mirror(TreeNode root){
//鲁棒性
if (root == null)
return null;
if (root.right == null || root.left == null)
return null;
for (int i=1;i<= TreeNode.getTreeHeight(root);i++){
mirrorRecursively(root, i);
}
TreeNode.printTree(root);
return root;
}
private static void mirrorRecursively(TreeNode root, int level){
if (root == null || level<1)
return ;
if (level == 1){
TreeNode temp = root.right;
root.right = root.left;
root.left = temp;
return ;
}
mirrorRecursively(root.left, level - 1);
mirrorRecursively(root.right, level - 1);
}
//2.前序遍历来实现
private static void pre_mirror(TreeNode root){
//鲁棒性
if (root == null)
return ;
if (root.right == null || root.left == null)
return ;
TreeNode temp = root.right;
root.right = root.left;
root.left = temp;
if (root.left != null)
pre_mirror(root.left);
if (root.right != null)
pre_mirror(root.right);
}
/*面试题28,对称的二叉树*/
private static boolean isSymmetrical(TreeNode root){
if (root == null)
return false;
List<Object> pre_order = new ArrayList<>();
List<Object> mirror_order = new ArrayList<>();
pre_order = preOrder(root, pre_order);
System.out.println(pre_order.toString());
mirror_order = mirror_order(root, mirror_order);
System.out.println(mirror_order.toString());
return pre_order.equals(mirror_order);
}
private static List<Object> mirror_order(TreeNode root, List<Object> result){
if (root == null) {
result.add(null);
return result;
}
result.add(root.val);
mirror_order(root.right, result);
mirror_order(root.left, result);
return result;
}
/* preorder on binary tree, using recursive way*/
private static List<Object> preOrder(TreeNode root,List<Object> result){
if (root==null){
result.add(null);
return result;
}
result.add(root.val);
preOrder(root.left, result);
preOrder(root.right, result);
return result;
}
//<<剑指offer>>上的解法
private static boolean isSymmetrical_1(TreeNode root) {
return isSymmetrical_1(root, root);
}
private static boolean isSymmetrical_1(TreeNode root1, TreeNode root2) {
if (root1 == null && root2==null)
return true;
if (root1 == null || root2==null)
return false;
if (root1.val != root2.val)
return false;
return isSymmetrical_1(root1.right, root2.left) && isSymmetrical_1(root1.left, root2.right);
}
/*面试题29,顺时针打印矩阵*/
private static void clockwise_print(int[][] num, int width, int height, int start_x, int start_y) {
if (width <= 0 || height <= 0)
return;
//如果是一排,直接输出
if (width == 1 || height == 1) {
for (int i = start_x; i < width + start_x; i++) {
for (int j = start_y; j < height + start_y; j++) {
System.out.println(num[i][j]);
}
}
return;
}
//否则,输出四周
//打印第一行
for (int i = 0; i < width - 1; i++) {
System.out.println(num[start_y][i + start_x]);
}
//打印最后一列
for (int j = 0; j < height - 1; j++) {
System.out.println(num[j + start_y][width - 1 + start_x]);
}
//打印最后一行
for (int i = width - 1 + start_x; i > start_x; i--) {
System.out.println(num[height - 1 + start_y][i]);
}
//打印第一列
for (int j = height - 1 + start_y; j > start_y; j--) {
System.out.println(num[j][start_x]);
}
clockwise_print(num, width - 2, height - 2, start_x + 1, start_y + 1);
}
/*面试题30,包含min函数的栈*/
static Stack<Integer> m_data = new Stack();
static Stack<Integer> m_min = new Stack();
private static void push(Integer value) {
m_data.push(value);
// Integer peek_value = m_data.peek();
// m_min.push(peek_value < value ? peek_value : value);
if (m_min.empty() && value < m_data.peek())
m_min.push(value);
else
m_min.push(m_min.peek());
}
private static Integer pop() {
if (!m_data.empty() && !m_min.empty()) {
m_min.pop();
return m_data.pop();
}
return 0;
}
private static Integer min() {
if (!m_min.empty() && !m_data.empty()) {
return m_min.pop();
}
return 0;
}
/*面试题31,栈的压入,弹出序列
* 利用一个辅助栈来完成.
* 1.如果下一个弹出数字刚好是栈顶元素,则直接弹出.
* 2.如果下一个弹出数字P不是栈顶元素,且push_seq中还有数字,则继续讲push_seq中的数字压入栈中,直到压入的是数字P.
* 3.如果所有数字都已经压入栈中,还没有找到P,则返回false;
* */
private static boolean isPopOrder(int[] push_seq, int[] pop_seq) {
if (push_seq == null || pop_seq == null)
return false;
Stack<Integer> s1 = new Stack();
Stack<Integer> s2 = new Stack();
int i = 0; //push_seq
int p = 0;
while (p<pop_seq.length){
if (!s1.empty() && s1.peek() == pop_seq[p]) {
s2.push(s1.pop());
p++;
}else if (i<push_seq.length){
while (i<push_seq.length && push_seq[i] != pop_seq[p])
s1.push(push_seq[i++]);
if (i > push_seq.length-1)
return false;
else
s1.push(push_seq[i++]);
}else if (s1.peek() != pop_seq[p]){
return false;
}
}
return true;
}