剑指offer:
JZ1-二维数组查找
思路一
##二分查找-把每一行看成有序递增的数组,利用二分查找,通过遍历每一行得到答案,时间复杂度是nlogn
public class Solution{
public boolean Find(int target, int [][] array){
for(int i=0;i<array.length;i++){
int low=0;
int high=array[i].length-1;
while(low<=high){
int mid=(low+high)/2;
if(target>array[i][mid])
low=mid+1;
else if(target<array[i][mid])
high=mid-1;
else
return true;
}
}
return false;
}
}
思路二
#利用二维数组由上到下,由左到右递增的规律,那么选取右上角或者左下角的元素a[row][col]与target进行比较,
#当target小于元素a[row][col]时,那么target必定在元素a所在行的左边,
#即col--;
#当target大于元素a[row][col]时,那么target必定在元素a所在列的下边,
#即row++;
public class Soution{
public boolean Find(int[][]array,int target){
int row=0;
int col=array[0].length-1;
while(row<=array.length-1&&col>=0){
if(target==array.length[row][col])
return true;
else if(target>array[row][col])
row++;//缩小范围
else
col--;
}
return false;
}
}
JZ2-替换空格
/*
问题1:替换字符串,是在原来的字符串上做替换,还是新开辟一个字符串做替换!
问题2:在当前字符串替换,怎么替换才更有效率(不考虑java里现有的replace方法)。
从前往后替换,后面的字符要不断往后移动,要多次移动,所以效率低下
从后往前,先计算需要多少空间,然后从后往前移动,则每个字符只为移动一次,这样效率更高一点。
空格替换成%20
例如:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
从后往前补充
*/
public class Solution{
public String replaceSpace(StringBuffer str){
int spacenum=0;//计算空格数
for(int i=0;i<str.length();i++){
if(str.charAt(i)==' ')
spacenum++;//有一个空格就增加
}
int indexold=str.length()-1;
int newlength=str.length()+spacenum*2;//替换的占有三个空间,加上原来永远有的一个空格空间,只需要再补充两个空间即可
int indexnew=newlength-1;//先计算好需要补充多少空格
str.setLength(newlength);//使str的长度扩大到转换成%20之后的长度,防止下标越界
//扩容
for(;indexold>=0&&indexold<newlength;--indexold){
if(str.charAt(indexold)==' '){
str.setCharAt(indexnew--,'0');//从后往前,所以需要自减
str.setCharAt(indexnew--,'2');//setCharAt将字符放到指定的位置
str.setCharAt(indexnew--,'%');
}else{
str.setCharAt(indexnew--,str.charAt(indexold));
}
}
return str.toString();
}
}
JZ3-从尾到头打印链表
方法一
public class Solution{
ArrayList<Integer>arrayList=new ArrayList<Integer>();
public ArrayList<Integer>printListFromTailToHead(ListNode listNode){
if(listNode!=null){
this.printListFromTailToHead(listNode.next);
arrayList.add(listNode.val);
}
return arrayList;
}
}
方法二:
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> list = new ArrayList<Integer>();
while(listNode != null){
list.add(listNode.val);
listNode = listNode.next;
}
Collections.reverse(list);//使用Collections的reverse方法,直接将list反转
return list;
}
}
JZ-4-重建二叉树
public class Solution{
public TreeNode reConstructBinaryTree(int[]pre,int[] in){//前序遍历和中序遍历序列
TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
private TreeNode reConstructBinaryTree(int[] pre,int startPre,int endPre,int[] i,int startIn,int endIn){
// 前序 前序开始 前序结束 中序开始 中序结束
if(startPre>endPre||startIn>endIn)
return null;
TreeNode root=new TreeNode(pre[startPre]);//根节点是前序的第一个节点
for(int i=startIn;i<=endIn;i++) //i是中序的节点,从中序的节点从前往后遍历
if(in[i]==pre[startPre]){//中序的第一个节点与中序的节点相等的确定根节点
root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);//找出对应的左节点和右节点
//
root.rigth=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in.i+1,endIn);
break;
}
return root;
}
}
JZ5-用两个栈实现队列
import java.util.Stack;
public class Solution{
Stack<Integer>stack1=new Stack<Integer>();
Stack<Integer>stack2=new Stack<Integer>();
public void push(int node){
stack1.push(node);
}
public int pop(){
if(stack!.empty()&&stack2.empty()){
throw new RuntimeException("Queue is empty");
}
if(stack2.empty()){
while(!stack1.empty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
//1 2 3 4 5进栈1 结果从下往上分别是 1 2 3 4 5
//取stack1栈顶元素分别 5 4 3 2 1 分别进stack2 顺序从下向上是 5 4 3 2 1
//栈2出栈 顺序使1 2 3 4 5 和最初结果一样
empty() 堆栈为空则返回真
pop() 移除栈顶元素
push() 在栈顶增加元素
size() 返回栈中元素数目
top() 返回栈顶元素
JZ6-旋转数组中的最小数字
本质就是找到数组中最小的值
public class Solution{//二分查找
public int minNumberInRotateArray(int[]array){
int low=0;int high=array.length-1;
while(low<high){
int mid=low+(high-low)/2;
if(array[mid]>array[high]){
low=mid+1;
}else{
high=mid;
}
}
return array[low];
}
}
JZ7-斐波那契数列
#循环实现
public class Solution{
public int Fibonacci(int n){
int preNum=1;
int prePreNum=0;
int result=0;
if(n==0)
return 0;
if(n==1)
return 1;
for(int i=2;i<=n;i++){
result=preNum+prePreNum;
prePreNum=preNum;
preNum=result;
}
return result;
}
}
JZ8-跳台阶
public class Solution{
public int JumpFloor(int target){
if(target==1)
return 1;
int f1=1,f2=1,ret=0;
for(int i=2;i<=target;i++){
ret=f1+f2;
f1=f2;
f2=ret;
}
return ret;
}
}
JZ9-变态跳台阶
public class Solution{
public int JumpFloorII(int target){
if(target<=0){
return -1;
}else if(target==1){
return 1;
}else{
return 2*JumpFloorII(target-1);
}
}
}
JZ-10矩形覆盖
public class Solution{
public int RectCover(int target){
if(target<3){
return target;
}
return RectCover(target-1)+RectCover(target-2);
}
}
JZ-11 二进制中1的个数
public class Solution{
public int NumberOf1(int n){
int sum=0;
while(n!=0)
{
sum++;
n=(n-1)&n;
}
return sum;
}
}
JZ-12 数值的整数次方
5^2 整数的求幂运算
public class Solution{
public double Power(double base,int exponent){ //底 - 指数
if(exponent==0) return 1 //指数为0,直接输出1 1 ^0=1
if(Math.abs(base)<=0.000000000001) return 0;//Math.abs 绝对值 底为0 则0^5=0
boolean reverseFlag=exponent<0;//指数为负数,则结果要求取倒数
exponent=Math.abs(exponent);//先对负数求取绝对值
double result=1;
while(exponent-- >0){ //现在确定指数的值均为正
result *=base;//result =result*base
}
return reverseFlag?1/result:result;//负数就是求倒数 整数就是正常结果
}
}
JZ-13调整数组顺序的使得奇数位于偶数之前
奇数偶数数组数据分离
public class Solution{
public void reOrderArray(int[] array){
for(int i=0;i<array.length-1;i++)//i的目的是对当前未知上的元素进行偶奇交换 之后遍历数组上的每个点,确保偶奇交换彻底
for(int j=0;j<array.length-1;j++){
if(array[j]%2==0&&array[j+1]%2==1){//j偶数 j+1奇数 偶数奇数就交换未知
int temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
}
}
}
}
JZ-14 链表中倒数第K个节点。
倒数的话,思路都应该反过来
public class Solution{
public ListNode FindKthToTail(ListNode head,int k){
ListNode p,q;//定义两个链表
p=q=head;//定义两个链表的头节点
int i=0;
for(;p!=null;i++){
if(i>=k){
q=q.next;
p=p.next
}
return i<k?null:q;
}
}
}
方法二:
public class Solution{
public ListNode FindKthToTail(ListNode head,int k){
ListNode pre=null,p=null
p=head;
pre=head;
//记录k值
int a=k;
//记录节点个数
int count=0;
while(p!=null){
p=p.next;//这两个链表是一样的,然后p先跑,
count++;
if(k<1){
pre=pre.next;//k=0 那么倒数第一个节点即是满足的条件
}
k--; // 4 3 2 1 0 -1 -2
}
if(count<a)return null;
return pre;
}
}
JZ-16 反转链表
public class Solution{
public ListNode ReverseList(ListNode head){
if(head==null)
return null;
ListNode p=head.next;
ListNode res=null;//设置一个新链表
while(head!=null){
head.next=res;
res=head;
head=p;
if(head!=null)
p=head.next;
}
return res;
}
}
public class Solution{
public ListNode ReverseList(ListNode head){
if(head==null)
return null;
ListNode pre=null;
ListNode next=null;
//当前节点是head,pre为当前节点的前一节点,next为当前节点的下一节点
//需要pre和next的目的是让当前节点从pre->head->next1->next2变成pre<-head next1->next2
//即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了
//所以需要用到pre和next两个节点
//1->2->3->4->5
//1<-2<-3 4->5
while(head!=null){
next=head.next;
head.next=pre;
pre=head;
head=next;
}
return pre;
}
}
JZ-17 树的子结构
public class Solution {
public static boolean HasSubtree(TreeNode root1, TreeNode root2) {
boolean result = false;
//当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
if (root2 != null && root1 != null) {
//如果找到了对应Tree2的根节点的点
if(root1.val == root2.val){
//以这个根节点为为起点判断是否包含Tree2 根节点相同,继续判断
result = doesTree1HaveTree2(root1,root2);
}
//如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2
if (!result) {
result = HasSubtree(root1.left,root2);
}
//如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2
if (!result) {
result = HasSubtree(root1.right,root2);
}
}
//返回结果
return result;
}
public static boolean doesTree1HaveTree2(TreeNode node1, TreeNode node2) {
//如果Tree2已经遍历完了都能对应的上,返回true
if (node2 == null) {
return true;
}
//如果Tree2还没有遍历完,Tree1却遍历完了。返回false
if (node1 == null) {
return false;
}
//如果其中有一个点没有对应上,返回false
if (node1.val != node2.val) {
return false;
}
//如果根节点对应的上,那么就分别去子节点里面匹配
return doesTree1HaveTree2(node1.left,node2.left) && doesTree1HaveTree2(node1.right,node2.right);
}
JZ18-二叉树的镜像
public class Solution{
public void Mirror(TreeNode root){
if(root=null){
return ;
}
TreeNode tmp=root.left;//先把树的左子树赋值给tmp 现在左孩子就是为空
root.left=root.right;//然后把右孩子赋值过去 变成左子树
root.right=tmp;//然后把最初的左子树赋值到右孩子
Mirror(root.left);//然后对左孩子作为根节点进行用相同的方法交换
Mirror(root.right)//然后对右孩子作为根节点进行相同的交换镜像
}
}
JZ19-顺时针打印矩阵
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
return list;
}
int up = 0;//上
int down = matrix.length-1;//下
int left = 0;//左边
int right = matrix[0].length-1;//右边
while(true){
// 最上面一行
for(int col=left;col<=right;col++){
list.add(matrix[up][col]);
}
// 向下逼近
up++;
// 判断是否越界
if(up > down){
break;
}
// 最右边一行
for(int row=up;row<=down;row++){
list.add(matrix[row][right]);
}
// 向左逼近
right--;
// 判断是否越界
if(left > right){
break;
}
// 最下面一行
for(int col=right;col>=left;col--){
list.add(matrix[down][col]);
}
// 向上逼近
down--;
// 判断是否越界
if(up > down){
break;
}
// 最左边一行
for(int row=down;row>=up;row--){
list.add(matrix[row][left]);
}
// 向右逼近
left++;
// 判断是否越界
if(left > right){
break;
}
}
return list;
}
}
JZ20-包含min函数的栈
import java.util.Stack;
public class Solution {
private Stack<Integer>stack1;//定义两个栈 stack1保存当前的node数据
private Stack<Integer>stack2;//stack2用于保存最小元素
public Solution(){
stack1=new Stack<>();
stack2=new Stack<>();
}
public void push(int node) {
stack1.push(node);
if(stack2.isEmpty()||stack2.peek()>node)//去栈顶的值但是不删除值
stack2.push(node);//栈2中的栈顶值大于node则把这个较小的值放入到栈2中 因为栈2的目的就是为了存放较小的值
else
stack2.push(stack2.peek());//说明当前stack2元素是比较小的,符合要求
//peek取栈顶元素,保留
}
public void pop() {//pop 取栈顶元素,并且删除
stack1.pop();
stack2.pop();
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();//最小的值就是栈2中栈顶最小值。
}
}
企业真题:
QY1-PDD1
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));//字符流的读取 控制框的输入
int n=Integer.parseInt(br.readLine());
String s=br.readLine();
String [] strs=s.split(" ");
long[] arr=new long[n];
for(int i=0;i<n;i++){
arr[i]=Long.parseLong(strs[i]);
}
long res=getAns(arr,n);
System.out.println(res);
}
public static long getAns(long[] arr,int n){ //数组 和数组长度
for(int i=0;i<3;i++){
for(int j=i+1;j<n;j++){
if(arr[i]<arr[j]){
long tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
}
}
long max1=arr[0]*arr[1]*arr[2];
for(int i=n-1;i>=n-2;i--){
for(int j=i-1;j>=0;j--){
if(arr[i]>arr[j]){
long tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
}
}
long max2=arr[0]*arr[n-2]*arr[n-1];
return Math.max(max1,max2);
}
}
华为机试-01-字串分割
import java.io.*;
import java.util.*;
public class Main{
public static void main(String[] args)throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input;
while((input=br.readLine())!=null){
StringBuilder sb = new StringBuilder(input);
while(sb.toString().length()>=8){
System.out.println(sb.toString().substring(0,8));
sb.delete(0,8);
}
if(sb.toString().length()<8 &&sb.toString().length()>0){
sb.append("00000000");
System.out.println(sb.toString().substring(0,8));
}
}
}
}
华为机试-02-统计每个月兔子的总数
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main{
public static void main(String[] args)throws Exception{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String line="";
while((line=br))
}
}
华为机试-进制转化
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
int main(){
string s;
while(cin>>s){
int bit=0;
int ans=0;
for(int s=s.length()-1;i>1;i--){//从16进制的个位开始,每位都转化成十进制
if(s[i]>='0'&&s[i]<='9')//数字符的转化
ans+=(s[i]-'0')*pow(16,bit++);
else if(s[i]>='A'&&s[i]<='F')//字母字符的转化
ans+=(s[i]-'A'+10)*pow(16,bit++);
}
cout<<ans<<endl;
}
return 0;
}
import java.util.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String input;
while((input = bf.readLine())!=null){
String temp = input.substring(2,input.length());
int sum = 0;
int length = temp.length();
for(int i= length-1;i>=0;i--){
char c = temp.charAt(i);
int tempNum = (int)c;
if(tempNum>=65){
tempNum = tempNum - 65 + 10;
}else{
tempNum = tempNum - 48;
}
sum = sum + (int) Math.pow(16, length-i-1)*tempNum;
}
System.out.println(sum);
}
}
}
华为机试-质数因子
#include<stdio.h>
int main(){
long n,i;
scanf("%ld",&n);
i=2;//从2开始
while(n!=1){
if(n%i==0){//取余 说明可以整除 每找到一个因数,直到除尽为止,找到的因数一定是质数
printf("%ld ",i);//打印
n=n/i;//取整 其实这道题的思路就是i++ 不断去求n是否可以对自增的i进行取余操作 n对i取整 表明n=n/i和之间存在乘积关系
}
else
i++;
}
}
import java.io.*;
import java.util.*;
//思路同上
public class Main{
public static void main(String[] args) throws Exception{
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
String str="";
while(null!=(str=bf.readLine())){
System.out.println(factor(Integer.valueOf(str)));
}
}
public static String factor(int num){
StringBuffer sb=new StringBuffer();
for(int i=2;i<Math.sqrt(num);i++){
if(num%i==0){
sb.append(i).append(" ");
num /=i;
i --;
}
}
return sb.append(num).append(" ").toString();
}
}
华为机试-统一大写字母
#include<stdio.h>
#include<string.h>
int main(){
char a[65536];
int i,k;
while(scanf("%s",a)!=EOF){//输入进来的字符 EOF 只要bai文件还有IO的输入,循环就du可以继续zhi进行
k=0;
for(int i=0;i<strlen(a);i++){//strlen计算字符串长度
if(a[i]<=90&&a[i]>=65){// A Z
k=k+1;
}
}
printf("%d\n",k);
}
return 0;
}
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader buff=new BufferedReader(new InputStreamReader(System.in));
String str="";
while((str=buff.readLine())!=null){
String s=str;
System.out.println(getResult(s));
}
}
public static int getResult(String str){
int x=0;
for(int i=0;i<str.length();i++){
if(str.charAt(i)>='A'&&str.charAt(i)<='Z'){//统计个数
x++;
}
}
return x;
}
}
华为机试-字符逆序
#include<cstdio>
const int MAX=1e9;
using namespace std;
char str[MAX];
int main(){
int top=-1;
char c=getchar();
while(c!='\n'){
top++;
str[top]=c;
c=getchar();
}
while(top!=-1){
printf("%c",str[top]);
top--;
}
return 0;
}
排序:
冒泡排序
packahe leetcode;
public class bubbleSort{
public static void bubbsort(int[]arr){
for(int i=0;i<arr.length-1;i++){//遍历数组
for(int j=0;j<arr.length-i-1;j++){//内循环
if(arr[j]<arr[j+1]){//相邻两个之间比较大小,然后交换值。
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
public static void main(String[] args){
int[] arr={9,6,7,8,1,3,5,2,0};
bubbsort(arr);
for(int i:arr){
System.out.println(i+"\t");
}
}
}
堆排序
package leetcode
public class HeapSort{
public static void main(String[] args){
int []arr={16,7,3,20,17,8};
heapSort(arr);
for(int i:arr){
System.out.println(i+"\t");
}
}
private static void heapSort(int[] arr){
for(int i=(arr.length-1)/2;i>=0;i--){
adjustHeadp(arr,i,arr.length);
}
//调整堆结构+交换堆顶元素与末尾元素
for(int i=arr.length-1;i>0;i--){
//将堆顶元素与末尾元素交换
int temp=arr[i];
arr[i]=arr[0];
arr[0]=temp;
//重新对堆进行调整
adjustHeap(arr,0,i);
}
}
private static void adjustHeap(int[]arr,int parent,int length){
//将temp作为父节点
int temp=arr[parent];
//左孩子
int lChild=2*parent+1;
while(lChild<length){
//右孩子
int rChild=lChild+1;
if(rChild<length&&arr[lChild]<arr[rChild]){
lChild++;
}
//如果父节点的值大于孩子的值,直接结束
if(temp>=arr[lChild]){
break;
}
//孩子节点赋值给父节点
arr[parent]=arr[lChild];
//选取左孩子节点,继续向下筛选
parent=lChild;
lChild=2*lChild+1;
}
arr[parent]=temp;
}
}