11、二进制中1的个数
题目:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:解决这道题的思路比较简单,就是将整数转换为二进制,然后得到二进制中1的个数,有两种方法:
原码、补码、反码基础知识
正整数的原码、补码和反码相同
负数-5的原码,1000 0101,即在正整数的基础上加上符号位,反码则是除符号位外,每一位都取反,即1111 1010,补码则是在反码的基础上+1,即1111 0110
- 方法一
直接调用Integer中的库函数toBinaryString转换为二进制,把该二进制转换为字符数组,循环判断字符是否为1。
- 方法二
采用移位的策略,假设数字12转换为二进制为1100,减1后就变为1001,如果将(1100)&(1001)=1000,利用这个特性,我们可以计算出二进制中1的个数。
调用库函数
public class Solution {
public int NumberOf1(int n) {
int result=0;
char[] ch=Integer.toBinaryString(n).toCharArray();
for(int i=0;i<ch.length;i++){
if(ch[i]=='1'){
result++;
}
}
return result;
}
}
移位操作
public class Solution {
public int NumberOf1(int n) {
int result=0;
while(n!=0){
result++;
n=n&(n-1);
}
return result;
}
}
12、数值的整数次方
题目:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0
思路:这道题有个陷阱需要考虑,就是exponent的正负不确定,所以这两种情况都要考虑到,
假设exponet为正,我们的思路通常是这样的:
①假如exponent为0,直接返回1
②假如exponent,不为0,我们可以利用for循环不断的累乘
假如exponent为负,我们不妨对exponent=-exponent,然后利用exponent为正式计算base的exponent,对于最后的输出结果,我们只需要对结果取倒数即可。
代码
public class Solution {
public double Power(double base, int exponent) {
double result=base;
int n=exponent;
if(exponent<0){
exponent=-exponent;
}
if(exponent==0){
return 1;
}
for(int i=1;i<exponent;i++){
result*=base;
}
return n<0 ? 1/result : result;
}
}
13、调整数组顺序使得奇数位于偶数前面
题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
- 冒泡排序
冒泡排序是两两比较数组中的相邻元素,我们可以把这道题目看作为冒泡排序的变种,将交换条件变为判断相邻元素是否为奇数、偶数
- 插入排序
插入排序是通过移位的方式来完成交换的,我们也是同样的将条件变为判断相邻元素是否为奇数、偶数来到达排序的目的
冒泡排序
public class Solution {
public void reOrderArray(int [] array) {
for(int i=0;i<array.length-1;i++){
for(int j=0;j<array.length-1-i;j++){
if(array[j]%2==0&&array[j+1]%2!=0){
int temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
}
}
}
}
}
插入排序
public class Solution {
public void reOrderArray(int [] array) {
//插入坐标
int insertIndex=0;
//要插入的值
int insertValue=0;
//循环比较判断
for(int i=1;i<array.length;i++){
insertIndex=i-1;
insertValue=array[i];
while(insertIndex>=0&&array[insertIndex]%2==0&&insertValue%2!=0){
array[insertIndex+1]=array[insertIndex];
insertIndex--;
}
if(insertIndex+1!=i){
array[insertIndex+1]=insertValue;
}
}
}
}
14、链表中的倒数第K个结点
题目:输入一个链表,输出该链表中倒数第k个结点。
思路:这道题的关键点在于倒数第K个结点,最简单的做法就是先计算出链表中元素的个数count,然后利用index=(count-k)判断结点在链表中的正序位置。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head==null){
return null;
}
if(k<=0){
return null;
}
int count=1;
ListNode node=head;
while(head.next!=null){
head=head.next;
count++;
}
count=count-k;
if(count<0){
return null;
}
for(int i=0;i<count;i++){
node=node.next;
}
return node;
}
}
15、反转链表
题目:输入一个链表,反转链表后,输出新链表的表头。
思路:这道题的核心是怎样改变链表的指向,使得链表的顺序从尾指向前。
定义两个指针pre和next,pre为当前结点的前一结点,next为当前结点的下一结点,它们的目的是为了改变链表的顺序,使得pre->head->next1->next2变成pre<-head next1->next2,利用head.next=pre反转当前结点的指向,最后让head、next依次向后移动一个结点,继续下一次的指针反转。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null){
return null;
}
ListNode pre=null;
ListNode next=null;
while(head!=null){
//保存next结点
next=head.next;
//反转链表
head.next=pre;
//pre和next依次向后移动一个节点,继续进行下一次的反转
pre=head;
head=next;
}
return pre;
}
}
16、合并两个排序链表(16)
题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路:因为题目要求是将这两个链表合成单调不减的链表,所以我们可以不断的循环判断链表1和链表2中的元素值放入一个新的链表中。步骤如下
- 初始化新链表
- 比较判断链表1和链表中的值,并放入新的链表
- 不断循环直到放入最后一个元素
代码
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null&&list2==null){
return null;
}else if(list1==null&&list2!=null){
return list2;
}else if(list1!=null&&list2==null){
return list1;
}
ListNode head=new ListNode(-1);
ListNode node=head;
while(list1!=null&&list2!=null){
if(list1.val<list2.val){
node.next=list1;
list1=list1.next;
node=node.next;
}else{
node.next=list2;
list2=list2.next;
node=node.next;
}
}
while(list1!=null){
node.next=list1;
list1=list1.next;
node=node.next;
}
while(list2!=null){
node.next=list2;
list2=list2.next;
node=node.next;
}
return head.next;
}
}
17、树的子结构
题目:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
思路:这道题的重点是理解子树的定义,即子树就是除根结点外,其余结点组成的互不相交的有限集合称为子树。我们结合和代码来讲解这道题的思路
1、首先设置标志位result = false,因为一旦匹配成功result就设为true,剩下的代码不会执行,如果匹配不成功,默认返回false,也就证明这两课二叉树的根结点不匹配,所以就需要利用树1的左右子结点去匹配树2(采用递归的思想)
2、如果根节点相同则递归调用DoesTree1HasTree2()
3、注意null的条件,HasSubTree中,如果两棵树都不为空才进行判断,DoesTree1HasTree2中,如果Tree2为空,则说明第二棵树遍历完了,即匹配成功,tree1为空有两种情况
- 如果tree1为空&&tree2不为空则说明不匹配
- 如果tree1为空,tree2为空则说明匹配
代码
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
boolean result=false;
if(root1!=null&&root2!=null){
if(root1.val==root2.val){
result= doesTree1HasTree2(root1,root2);
}
//往左子树递归
if(!result) result= HasSubtree(root1.left,root2);
//往右子树递归
if(!result) result= HasSubtree(root1.right,root2);
}
return result;
}
public boolean doesTree1HasTree2(TreeNode root1,TreeNode root2){
if(root1==null&&root2!=null){
return false;
}
if(root2==null){
return true;
}
if(root1.val!=root2.val){
return false;
}
//左右子树递归检查
return doesTree1HasTree2(root1.left,root2.left)&&doesTree1HasTree2(root1.right,root2.right);
}
}
18、二叉树的镜像(18)
题目:操作给定的二叉树,将其变换为原二叉树的镜像。
二叉树镜像的定义:
思路:刷了那么多题目,我们发现关于二叉树的题目大部分都是用递归来解决的,这道题也不例外,依旧采用递归来解决
结合代码来讲解下这道题的思路
1、首先判断二叉树的根结点是否为空,为空时不成立,
2、判断该根结点的左右子树是否同时为空,为空时不需要变换位置
3、若不同时为空,交换左右子树的位置,
4、采用递归的思想对剩下的结点做判断并交换位置
代码
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public void Mirror(TreeNode root) {
//采用递归的思想
if(root==null){
return ;
}
if(root.left==null&&root.right==null){
return ;
}
TreeNode proot=root.left;
root.left=root.right;
root.right=proot;
if(root.left!=null){
Mirror(root.left);
}
if(root.right!=null){
Mirror(root.right);
}
}
}
19、顺时针打印矩阵
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: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.
方式一:
定义四个变量分别表示左、右、上、下,循环条件可以是(left<=right&&top<=bottom)
定义四个for循环分别进行从左向右、从上到下、从右到左、从下到上的遍历
方式二:
代码采用方式一的思路编写,
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> result=new ArrayList<Integer>();
//定义四个变量:左,上,右,下
int left=0,top=0,right=matrix[0].length-1,bottom=matrix.length-1;
while(left<=right&&top<=bottom){
for(int i=left;i<=right;i++) result.add(matrix[top][i]);
for(int i=top+1;i<=bottom;i++) result.add(matrix[i][right]);
for(int i=right-1;i>=left&&top<bottom;i--) result.add(matrix[bottom][i]);
for(int i=bottom-1;i>top&&right>left;i--) result.add(matrix[i][left]);
top++;left++;right--;bottom--;
}
return result;
}
}
20、包含min函数的栈
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。
思路:这道题目有两种方式可以解决,第一种方式是直接利用Iterator类,在实际的笔试中,这种方法应该是不让使用的,所以放弃,有兴趣的可以看看代码一。第二种方式定义了两个栈,totalStack用于存放正常添加的值,littleStack用于存放最小的值,要保证两个栈中的数量一致,即当新添加的元素小于littleStack的栈顶元素时,littleStack直接push新元素,反之,littleStack向栈顶添加原栈顶元素,为什么要使得两个栈中的元素的数量保持一致呢?这是保证两个栈执行pop操作时,littleStack栈顶元素永远是栈中的最小值,实现操作见代码二。
代码一:
import java.util.Stack;
import java.util.Iterator;
public class Solution {
Stack<Integer> stack=new Stack<Integer>();
public void push(int node) {
stack.push(node);
}
public void pop() {
stack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
int min = stack.peek();
int tmp = 0;
Iterator<Integer> iterator = stack.iterator();
while (iterator.hasNext()){
tmp = iterator.next();
if (min>tmp){
min = tmp;
}
}
return min;
}
}
代码二
import java.util.Stack;
public class Solution {
Stack<Integer> totalStack=new Stack<Integer>();
Stack<Integer> littleStack=new Stack<Integer>();
public void push(int node) {
totalStack.push(node);
if(littleStack.empty()){
littleStack.push(node);
}else{
if(node<=littleStack.peek()){
littleStack.push(node);
}else{
littleStack.push(littleStack.peek());
}
}
}
public void pop() {
totalStack.pop();
littleStack.pop();
}
public int top() {
return totalStack.peek();
}
public int min() {
return littleStack.peek();
}
}