package com.overridere.twentytothirty;
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
/**
* 第十一题
* 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
*/
public int NumberOf1(int n) {
int count = 0;
/**
* 方式一:
* 将n的二进制数的每一位与1进行与运算,如果结果不为0则当前位置为1
* num初始化为0000 0001,逐步左位移,0000 0010....
*/
int num = 1;
while(num != 0){
if((n&num) != 0){
count++;
}
num <<= 1;
}
/**
* 方式二:
* n-1相当于从n的二进制数末尾遍历,遇见0就转换为1,遇见1则转化成0,然后停止
* 最后与n作位于运算就会抛弃掉那些改变的数,作用是只会遍历1,直到没有1
*/
while(n != 0){
n = (n-1)&n;
count ++;
}
return count;
}
/**
* 第十二题
* 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
*/
public double Power(double base, int exponent) {
if(base == 0)
return 0;
if(exponent == 0)
return 1;
int n = Math.abs(exponent);
double rel = 1;
//方式一:
// while(n > 0){
// rel *= base;
// n--;
// }
//方式二:
//rel = base * Power(base, n - 1);
/**
* 方式三:
* 思路:若exponent为13,转换为二进制则是1101,也就是2^3+2^2+0+2^0,
* 遍历 这个二进制,也就是向右位移,从右向左开始,第一个1的时候为2^0 = 1,第二个1的时候是2^2+2^0 = 5
* 最后一个1的时候为2^3+2^2+2^0 = 13,
*/
while(n > 0){
if((n&1) == 1) rel *= base;
base *= base; //2的倍数次方,遍历几次就是到了第几个位置上,二进制数据从右往左依次是2^0,2^1,2^2,2^3...
n >>= 1; //向右位移
}
return exponent < 0?1/rel:rel;
}
/**
* 第十三题
* 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,
* 所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
*/
public void reOrderArray(int [] array) {
//方式一:空间换时间
int left = 0;
// int[] newArray = new int[array.length];
// int right = newArray.length - 1;
// for(int i = 0; i < array.length; i ++){
// if(array[i] % 2 != 0)
// newArray[left++] = array[i];
// if(array[array.length-1-i] % 2 == 0)
// newArray[right--] = array[array.length-1-i];
// }
// array = newArray;
//
//方式二:一个一个移位
for(int i = 0; i < array.length; i ++){
if(array[i] % 2 != 0){
for(int j = i;j > left;j --){
int temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
}
left ++;
}
}
}
/**
* 第十四题
* 输入一个链表,输出该链表中倒数第k个结点。 不能使用数组、集合等。
*
* 思路:定义两个游标,一个在第i个位置上,一个在第i+k个位置上,
* 当第i+k个节点为尾节点的时候,第i个节点就是要寻找的节点
*/
public ListNode FindKthToTail(ListNode head,int k) {
if(head == null)
return null;
if(head.next == null)
return head;
int i = 0;
ListNode left = head;
ListNode right = head;
while(left != null){
left = left.next;
if(i >= k)
right = right.next;
i ++;
}
return i < k?null:right;
}
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
/**
* 第十五题
* 输入一个链表,反转链表后,输出链表的所有元素。 不能使用数组、集合等。
*
* 思路:定义一个节点保存上一次遍历的节点,遍历链表时,把当前节点指向上一次遍历的节点
*/
public ListNode ReverseList(ListNode head) {
if(head==null)
return null;
ListNode node=null;
ListNode current=head;
while(current!=null){
ListNode tmp = current; //临时保存当前遍历的节点
current = current.next; //这一条线为遍历线
//这一条线为转向线,将节点的指向反转
tmp.next = node; //当前遍历的节点的next指向上一次遍历的节点
node = tmp; //当前遍历的节点保存为历史遍历的节点
}
return node;
}
/**
* 第十六题
* 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
* 思路:保存头结点的前提下进行遍历排序
*/
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode listNode = null;
if(list1 == null)
return list2;
else if(list2 == null)
return list1;
/**
* 方式一:递归
* 第一次从头到尾遍历,第二次从尾到头返回值,最终返回的是已经遍历排好序的链表的头结点
*/
// if(list1.val < list2.val){
// listNode = list1;
// listNode.next = Merge(list1.next, list2);
// }else{
// listNode = list2;
// listNode.next = Merge(list1, list2.next);
// }
/**
* 方式二:循环
* 一个变量listNode存储头结点不变,一个变量current作为游标进行遍历
* 刚开始两个变量都指向头结点的‘地址’,而后来listNode不变,current进行遍历改变了头结点地址的内容
* 所以改变的东西也适用于那个‘不变’的listNode
*/
ListNode current = null;
while(list1 != null && list2 != null){
if(list1.val < list2.val){
if(listNode == null)
listNode = current = list1;
else{
current.next = list1;
current = current.next;
}
list1 = list1.next;
}else{
if(listNode == null)
listNode = current = list2;
else{
current.next = list2;
current = current.next;
}
list2 = list2.next;
}
}
if(list1 == null)
current.next = list2;
else
current.next = list1;
return listNode;
}
/**
* 第十七题
* 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
*
* 思路:遍历A树的所有节点分别于B树的头结点比较是否相等,如果相等再比较儿子
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
//这一层递归是在root1链表中遍历所有节点分别与root2链表的父节点进入下一层递归进行是否相等的比较
//只要有一个节点符合就为true
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if(root1 == null || root2 == null)
return false;
return isSubtree(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
}
//这一层递归是将root1中的所有节点依次与root2中的父节点比较,如果父节点相同再比较子节点
public boolean isSubtree(TreeNode root1,TreeNode root2){
if(root1 == null && root2 != null)
return false;
else if(root2 == null)
return true;
else if(root1.val == root2.val){
return isSubtree(root1.left, root2.left) && isSubtree(root1.right, root2.right);
}
return false;
}
/**
* 第十八题
* 操作给定的二叉树,将其变换为源二叉树的镜像。
* 输入描述:二叉树的镜像定义:每一层的节点顺序置反
* 源二叉树:
* 8
* 6 10
* 5 7 9 11
* 镜像二叉树:
* 8
* 10 6
* 11 9 7 5
*/
public void Mirror(TreeNode root) {
if(root == null)
return;
//方式一:递归实现
TreeNode treeNode = root.left;
root.left = root.right;
root.right = treeNode;
Mirror(root.left);
Mirror(root.right);
/**
* 方式二:置反一个节点的两个儿子就将两个儿子塞入栈中,下一次置反那两个儿子,直到叶子节点没儿子
*/
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(stack.size() > 0){
TreeNode tree = stack.pop();
if(tree.left != null || tree.right != null){
TreeNode t = tree.left;
tree.left = tree.right;
tree.right = t;
}
if(tree.left != null)
stack.push(tree.left);
if(tree.right != null)
stack.push(tree.right);
}
}
/**
* 第十九题
* 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵:
* 1 2 3 4
* 5 6 7 8
* 9 10 11 12
* 13 14 15 16
* 则依次打印出数字 1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
*/
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> result = new ArrayList<Integer> ();
if(matrix.length==0) return result;
int row = matrix.length,col = matrix[0].length;
if(col==0) return result;
int layers = (Math.min(row,col)-1)/2+1; //圈数或者说与外围的相差的层数
for(int i=0;i<layers;i++){
for(int k = i;k<col-i;k++) //1,2,3,4
result.add(matrix[i][k]);
for(int j=i+1;j<row-i;j++) //8,12,16
result.add(matrix[j][col-i-1]);
for(int k=col-i-2;(k>=i)&&(row-i-1!=i);k--) //15,14,13
result.add(matrix[row-i-1][k]);
for(int j=row-i-2;(j>i)&&(col-i-1!=i);j--) //9,5
result.add(matrix[j][i]);
}
return result;
}
/**
* 第二十题
* 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
*
* 思路:一个栈用来保存数据,一个栈用来保存push历史上所有曾最小的值,
* 因为栈是按顺序进栈出栈的,所以最小值栈中的顺序与数据栈中对应值的顺序一致的
* 意思是说当没删除到最小值的时候,mini栈顶还是最小值,当删除到最小值的时候,mini栈中的次最小值就是最小值
*/
public class MyStack {
Stack<Integer> stack = new Stack<>();
Stack<Integer> miniStack = new Stack<>();
public void push(int node) {
if(miniStack.isEmpty())
miniStack.push(node);
else if(node < miniStack.peek())
miniStack.push(node);
stack.push(node);
}
public void pop() throws Exception{
if(stack.pop() == miniStack.peek())
miniStack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return miniStack.peek();
}
}
}
剑指offer 11-20
最新推荐文章于 2024-10-02 23:40:03 发布