剑指Offer刷题整理(11-20),Java版

题目来自牛客网

文章目录

    • 11.二进制中“1”的个数
      • 题目描述
      • 思路:
      • 算法实现
    • 12.数值的整数次方
      • 题目描述
      • 思路:
      • 算法实现
    • 13.调整数组顺序是奇数位于偶数前边
      • 题目描述
      • 思路:
      • 算法实现
    • 14.链表倒数第k个节点
      • 题目描述
      • 思路:
      • 算法实现
    • 15.翻转链表
      • 题目描述
      • 思路:
      • 算法实现
    • 16.合并两个排序的链表
      • 题目描述
      • 思路:
      • 算法实现
    • 17.树的子结构
      • 题目描述
      • 思路:
      • 算法实现
    • 18.二叉树的镜像
      • 题目描述
      • 思路:
      • 算法实现
    • 19.逆时针打印矩阵
      • 题目描述
      • 思路:
      • 算法实现
    • 20.包含min函数的栈
      • 题目描述
      • 思路:
      • 算法实现

11.二进制中“1”的个数

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路:

提到二进制首先想到的最基本的除二取余算法,但是这题没有这么简单,因为cpu执行乘除法的指令周期要长, 解决办法是位运算。位运算的指令周期较短。二进制位运算右移相当于除以2,左移相当于乘2。然后用将1与该二进制数进行与运算,即可统计出末位1的个数。但是要注意的一点是,负数的话左边第一位是1,对负数进行右移会进入死循,为了 解决这一问题可以改为左移,然后同时也将进行与运算的1左移。

算法实现

方法一:

class Solution11_1{//方法1,右移,但是负数时会进入死循环
	  public int NumberOf1(int n) {
		  int count=0;
	       while(n!=0) {
	    	   if((n&1)==1) {
	    		   count++;
	    	   }
	    	   n=n<<1;
	       }
		  return count;
	    }	
}

方法二;

class Solution11_2{//方法2,左移
	  public int NumberOf1(int n) {
		  int count=0;
		  int flag=1;
	       while(flag!=0) {
	    	   if((n&flag)==1) {
	    		   count++;
	    	   }
	    	   flag=flag<<1;
	       }
		  return count;
	    }	
}

方法三:来源牛客网神回复

class Solution11_3{//方法3,比较有新意的解法,一个数减去1在和原来的数进行与运算,会把该数最右边的1变成0
	  public int NumberOf1(int n) {
		  int count=0;
	       while(n!=0) {
	    	   ++count;
	    	   n=(n-1)&n;
	       }
		  return count;
	    }	
}

12.数值的整数次方

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

思路:

方法一:分类讨论,1:base=0;2:exponent=1;3:exponent>=0;4:exponent<0;然后用快速幂
方法二:公式:

  •   	    a^n={
      			   a^(n/2)*a^(n/2)            n为偶数;
      			   a^((n-1)/2)*a^((n-1)/2)*a  n为奇数;
      			}     
    

算法实现

方法一:分类讨论

class Solution_12_1{
	public double Power(double base, int exponent) {
		double res = 0;
       if(equal(base,0.0)) {
    	   return 0.0;
       }
       if(exponent==1) {
    	   return base;
       }
       if(exponent>=0) {
    	   res = Pow(base,exponent);
       }
       if(exponent<0) {
    	   res = 1.0/Pow(base,-exponent);
       }  
       return res;
	  }
	boolean equal(double a,double b) {
		final double acc = 0.000001;
		if(((a-b)>0&&(a-b)<=acc)||((b-a)>=0&&(b-a)<=acc)){
			return true;
		}
		else {
			return false;
		}
	}
	double Pow(double base,int exponent) {
		double ans=1;
		while(exponent!=0) {
			if((exponent & 1)!=0) {
				ans *= base;
			}
			base *= base;
			exponent >>= 1;
		}
		return ans;
	}
}

方法二:使用公式

class Solution_12_2{
	public double Power(double base, int exponent) {
        if(exponent == 0) {
        	return 1;
        }
        if(exponent == 1) {
        	return base;
        }
        double result = Power(base,exponent >> 1);
        result *= result;
        if((exponent & 1) == 1) {
        	result *=base;
        }
        return result;
	  }
}

13.调整数组顺序是奇数位于偶数前边

题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路:

方法一:快排思想,会改变奇数和奇数,偶数和偶数之间的相对位置
方法二:将传入的数组复制一份,然后依次遍历奇数和偶数插入原数组

算法实现

方法一:

class Solution_13{//快排思想,顺序会改变
	public void reOrderArray(int [] array) {
        int len=array.length;
        int start=0,end=len-1;
        while(start

方法二:

class Solution13_2 {
    public void reOrderArray(int [] array) {
        int len=array.length;
        int []a=new int [len];
        for(int i=0;i

14.链表倒数第k个节点

题目描述

输入一个链表,输出该链表中倒数第k个结点。

思路:

方法一:双指针,即使用两个指针,第一个比第二个先走k步之后,然后两个指针一起走,当第一个指针达到终点的时候,第二个指针指向的就是倒数第k个节点
方法二:使用栈,先将链表入栈,然后出栈,倒数第k个出栈的就是要找的数

算法实现

方法一:

class Solution14 {
    public ListNode FindKthToTail(ListNode head,int k) {
    	if(head==null||k==0) {
    		return null;
    	}
    	int len=1;
    	ListNode p =head;
    	while(p!=null) {
    		if(p.next!=null) {
    			len++;  			
    		}
    		p=p.next;
    	}
    	if(k>len) {
    		return null;
    	}
    	ListNode pre=head;
    	for(int i=0;i

方法二:

class Solution14_2 {
    public ListNode FindKthToTail(ListNode head,int k) {
         Stack stack = new Stack();
        if(head == null || k ==0 ){
            return null;
        }
        int count=0;
         while(head!=null){
             stack.push(head);
             head=head.next;
             count++;
         }
        if(count

15.翻转链表

题目描述

输入一个链表,反转链表后,输出新链表的表头。

思路:

使用双指针,这里要注意的一点是断链的过程,一定要先将head指向下一个节点在调整p2

算法实现

class Solution15 {
    public ListNode ReverseList(ListNode head) {
    	if(head==null) {
    		return null;
    	}
    	ListNode p1,p2;
    	p1=head;
    	if(p1.next==null) {
    		return p1;
    	}
    	head=head.next;
    	p1.next=null;
    	while(head!=null) {
        	p2=head;
        	head=head.next;//注意:一定要先将head指向下一个再调p2
        	p2.next=p1;
        	p1=p2;
        	
    	}
    	return p1;
    }
}

16.合并两个排序的链表

题目描述

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路:

这里主要是比较大小,然后将符合条件的节点断开接入链表就可以,不过要注意的有一点,多使用判断能减少一些不必要的插入操作

算法实现

class Solution16 {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1==null&&list2==null) {
        	return null;
        }
        if(list1==null&&list2!=null) {
        	return list2;
        }
        if(list1!=null&&list2==null) {
        	return list1;
        }
        ListNode p=null;
        if(list1.val<=list2.val) {
         	p=list1;
         	list1=list1.next;
         }else {
         	p=list2;
         	list2=list2.next;
         }
        ListNode q=p;
        while(list1!=null||list2!=null) {
        	if(list1==null&&list2!=null) {
             	q.next=list2;
             	break;
             }
             if(list1!=null&&list2==null) {
            	 q.next=list1;
            	 break;
             }
        	 if(list1.val<=list2.val) {
             	q.next=list1;
             	q=q.next;
             	list1=list1.next;
             }else {
             	q.next=list2;
             	q=q.next;
             	list2=list2.next;
             }
        	 
        }
        return p;
    }
}

17.树的子结构

题目描述

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路:

任意顺序遍历即可

算法实现

class Solution17 {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
    	boolean flag = false;
    	if(root1!=null && root2!=null) {
    		if(root1.val==root2.val) {
    			flag=IsSubtree(root1,root2);
    		}
    		if(!flag) {
    			flag=HasSubtree(root1.left, root2);
    		}
    		if(!flag) {
    			flag=HasSubtree(root1.right, root2);
    		}
    	}
        return flag;
    }

	private static boolean IsSubtree(TreeNode root1, TreeNode root2) {
		if(root2==null) {
			return true;
		}
		if(root1==null) {
			return false;
		}
		if(root1.val!=root2.val) {
			return false;
		}
		return IsSubtree(root1.left, root2.left)&&IsSubtree(root1.right, root2.right);
	}
}

18.二叉树的镜像

题目描述

操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:

		源二叉树 
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	镜像二叉树
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5

思路:

任意顺序遍历即可

算法实现

class Solution18{
	  public void Mirror(TreeNode root) {
		  if(root==null) {
			 return ;
		  }
		  if(root.left!=null||root.right!=null) {
			  TreeNode t= root.left;
			  root.left=root.right;
			  root.right=t;
		  }
		  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.

思路:

首先确定圈数 ,然后以左上角的点和右下角的点为基准,逐圈打印

算法实现

class Solution19{
	public ArrayList printMatrix(int [][] matrix) {
	    ArrayList list = new ArrayList();
	    int l1=matrix.length;
	    int l2=matrix[0].length;
	    int circle ;//确定圈数
	    if(l1==0) {
	    	return list;
	    }
	    if(l1<=l2) {
	    	if(l1%2==0) {
	    		circle=l1/2;
	    	}else {
	    		circle=(l1/2)+1;
	    	}
	    }else {
	    	if(l2%2==0) {
	    		circle=l2/2;
	    	}else {
	    		circle=(l2/2)+1;
	    	}
	    }//确定圈数结束
	    int ux=0,uy=0,dx=l2,dy=l1;//u为左上角的点,d为右下角的点,x为横坐标,y为纵坐标
	    for(int i=0;i=ux&&uy!=dy;p--) {//第三圈,这里加个判断防止一行时重复打印
	    		list.add(matrix[dy-1][p]);
	    	}
	    	dy--;
	    	for(int q=dy-1;q>=uy&&ux!=dx;q--) {//第四圈,同上加判断防止重复打印
	    		list.add(matrix[q][ux]);
	    	}
	    	ux++;
	    }
	    return list;
    }

20.包含min函数的栈

题目描述

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

思路:

新建一个栈,栈顶记录最小值即可

算法实现

class Solution20{
	private Stack stack = new Stack();
	private Stack min = new Stack();

	public void push(int node) {
		stack.push(node);
		if (min.isEmpty()) {
			min.push(node);
		} else if (node <= min.peek()) {				
			min.push(node);
		}
	}

	public void pop() {
		
		int value=stack.pop();
		if(value==(min.peek())) {
			min.pop();
		}
	}

	public int top() {
		return stack.peek();
	}

	public int min() {
		return min.peek();
	}
}

你可能感兴趣的:(数据结构/算法)