剑指Offer-面试算法题

2023-05-16

1.二分查找(递归与非递归实现)

基本算法,掌握好循环条件

package com.company;

/**
 * Description :二分查找(递归与非递归实现)
 * Created by Wanbo
 * Date :2021/7/18
 */
public class offer1 {
//   非递归
    public static int binarySearch(int []arr, int num){
        int low =0, high = arr.length-1, mid = 0;
        while (low <= high){
            mid = (low + high)/2;
            if(arr[mid] == num){
                return mid;
            }
            else if(arr[mid] > num){
                high = mid-1;
            }
            else if(arr[mid] < num){
                low = mid+1;
            }
        }
        return -1;
    }

//    递归
    public static int recursiveBinarySearch(int arr[], int low, int high, int num){
        int mid = 0;
        if(low <= high) {
            mid = (low + high)/2;
            if(arr[mid] == num){
                return mid;
            }
            else if(arr[mid] > num){
                return recursiveBinarySearch(arr, low, high-1, num);
            }
            else if(arr[mid] < num){
                return recursiveBinarySearch(arr, mid+1, high, num);
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int arr[] = {1,3,5,7,9,10,12,15,20};
        System.out.println(binarySearch(arr,7));
        System.out.println(recursiveBinarySearch(arr,0,arr.length-1,7));
    }
}


2.二维数组中查找

两个for循环复杂度比较高,从右上或左下进行遍历查找,每遍历一次就能减少一行/列,降低复杂度

package com.company;

/**
 * Description :二维数组中查找
 * Created by Wanbo
 * Date :2021/7/18
 */
public class offer2 {
//    右上或左下开始遍历,减少遍历范围,我采用右上
    public static boolean findNumIn2DArray(int array[][], int num) {
        if(array.length == 0 || array[0].length == 0){
            return false;
        }
        int rows = array.length;
        int columns = array[0].length;
        int i = 0;
        int j = columns - 1;
        while(i < rows && j >=0) {
            if(array[i][j] == num) {
                return true;
            }
            else if(array[i][j] > num) {
                j--;
            }
            else {
                i++;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        int arr[][] = {
                {1,2,3},
                {4,5,6},
                {7,8,9}
        };
        System.out.println(findNumIn2DArray(arr, 2));
    }
}


3.旋转数组中最小的数

旋转数组可以分为两个子数组,都是有序,且后面的子数组最大的要小于等于左边的子数组最小的元素,常规遍历复杂度为n,采用二分查找。

package com.company;

/**
 * Description :旋转数组中最小的数
 * Created by Wanbo
 * Date :2021/7/18
 */
public class offer3 {
    public static int minNumberInRotateArray(int [] array) {
        if(array.length==0){
            return 0;
        }
        int low = 0, high = array.length-1, mid = 0;
        while(low < high){
            if(array[low]<array[high]){
                return array[low];
            }
            mid = (high+low)/2;
            if(array[mid] > array[high]){
                low = mid+1;
            }else if(array[mid] < array[high])
            {
                high = mid;
            }else{
                //存在low high mid大小相同的情况,左移high,比较右边小的子数组
                high --;
            }
        }
        return array[low] ;
    }

    public static void main(String[] args) {
//        int arr[] = {3,4,5,1,2};
        int arr[] = {2,2,2,1,2};
        System.out.println(minNumberInRotateArray(arr));
    }
}


4.调整数组使得奇数在前偶数在后

    类似快排,双指针i,j,指向两端,往中间遍历
    i指向的为奇数跳过,j指向的为偶数跳过
    i指向偶数,j指向奇数交换值
    i=j时退出

package com.company;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * Description :调整数组使得奇数在前偶数在后
 * Created by Wanbo
 * Date :2021/7/18
 */
public class offer4 {
    /*
    * 类似快排,双指针i,j,指向两端,往中间遍历
    * i指向的为奇数跳过,j指向的为偶数跳过
    * i指向偶数,j指向奇数交换值
    * i=j时退出
    * */
    public static int[] adjustOddAndEven(int arr[]){
        int i = 0, j = arr.length-1, temp = 0;
        while(i < j){
            while(i<j && arr[i]%2 ==1){
                i++;
            }
            while(i<j && arr[j]%2 == 0){
                j--;
            }
            if(i < j) {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        return arr;
    }
    public static void main(String[] args) {
        int arr[] = {1,2,3,4,5,6,7};
        System.out.println(Arrays.toString(adjustOddAndEven(arr)));
    }
}


5.顺时针打印矩阵

找到打印规律,注意起始与终止的循环下标,添加到list中进行打印。

package com.company;
import java.util.ArrayList;

/**
 * Description :顺时针打印矩阵
 * Created by Wanbo
 * Date :2021/7/18
 */
public class offer5 {
    public static ArrayList<Integer> getList(int arr[][]) {
        ArrayList<Integer> list=new ArrayList<>();
        int row=arr.length, col=arr[0].length;
        if(arr.length == 0 || row<0 || col<0){
            return null;
        }
        int count=0;
        while(col>count*2 && row>count*2){
            getNum(list,arr,col,row,count);
            count++;
        }
        return list;
    }

    public static void getNum(ArrayList<Integer> list, int [][] arr,int col,int row,int start){
        int endrow=row-start-1;
        int endcol=col-start-1;
        //从左到右打印一行,行号为count,列号为count到endrow递增,添加row个数
        for(int i=start;i<=endcol;i++){
            list.add(arr[start][i]);
        }
        //从上往下打印,终止行号需大于起始行号,行号为count+1到endrow递增,添加col-1个数
        if(endrow>start){
            for(int i=start+1;i<=endrow;i++){
                list.add(arr[i][endcol]);
            }
        }
        //从右往左打印,终止列号要大于起始列号,添加row-1个数
        // 列号为endcol-1到count递减
        if(endrow>start && endcol>start){
            for(int i=endcol-1;i>=start;i--){
                list.add(arr[endrow][i]);
            }
        }
        //从下往上打印,终止行号至少比开始行号大1,行号为endrow-1到count+1递减,添加col-2个数
        if((endrow-start>1)&&endcol>start){
            for(int i=endrow-1;i>=start+1;i--){
                list.add(arr[i][start]);
            }
        }
    }

    public static void main(String[] args) {
        int arr[][] = {
                {1,2,3,4},
                {4,5,6,5},
                {7,8,9,6}
        };
        ArrayList<Integer> list = getList(arr);
        System.out.println(list.toString());
    }
}


6.数组中超过一半的数

排序找中位数,即使出现次数最多的数,根据数据规模,特征选择合适的排序算法,详见常见八大排序算法

package com.company;
/**
 * Description :数组中超过一半的数
 * Created by Wanbo
 * Date :2021/7/20
 */
public class offer6 {

//    排序找中位数,即使出现次数最多的数,用快排
    public static int getNum(int arr[]){
        rotate(arr,0,arr.length-1);
        return arr[arr.length/2];
    }

    public static int quickSort(int[] arr, int low, int high) {
        int i = low, j = high, temp = arr[low];
        while (i < j) {
            while (i < j && arr[j] >= temp) {
                j--;
            }
            if (i < j) {
                arr[i] = arr[j];
            }
            while (i < j && arr[i] <= temp) {
                i++;
            }
            if (i < j) {
                arr[j] = arr[i];
            }
        }
        arr[i] = temp;
        return i;
    }

    public static void rotate(int[] arr,int low, int high){
        if(arr == null || arr.length == 0){
            return;
        }
        if(low < high) {
            int pos = quickSort(arr, low, high);
            quickSort(arr, low, pos - 1);
            quickSort(arr, pos + 1, high);
        }
    }

    public static void main(String[] args) {
        int arr[] = {3,4,6,1,4,5,2,2,2,2,2,2};
        System.out.println(getNum(arr));
    }
}

7.统计一个数字在排序数组中出现的次数

for一次循环每次遇见key次数+1,复杂度为n,可以采用二分查找,找出数组中第一次与最后一次出现数字的位置,它们的差+1就是出现的次数,复杂度为logn

package com.company;

/**
 * Description :统计一个数字在排序数组中出现的次数
 * Created by Wanbo
 * Date :2021/7/20
 */
public class offer7 {
    public static int getNumOfCount(int arr[], int key){
        if(arr.length == 0 || arr == null){
            return 0;
        }
        int firstKey = 0, lastK = 0, count = 0;
        firstKey = getFirstK(arr, key);
        lastK = getLastK(arr, key);
        if(firstKey != -1 && lastK != -1){
            return (lastK-firstKey+1);
        }
        return 0;
    }
    public static int getFirstK(int arr[], int key){
        int low = 0, high = arr.length-1, mid = 0;
        while(low <= high){
            mid = (low+high)>>1;
            if(arr[mid] == key){
                if(arr[mid-1] < key){
                    return mid;
                }else {
                    high = mid-1;
                }
            }else if(arr[mid] < key){
                low = mid+1;
            }else {
                high = mid-1;
            }
        }
        return -1;
    }
    public static  int getLastK(int arr[], int key){
        int low = 0, high = arr.length-1, mid = 0;
        while(low <= high){
            mid = (low+high)>>1;
            if(arr[mid] == key){
                if(arr[mid+1] > key){
                    return mid;
                }else {
                    low = mid+1;
                }
            }else if(arr[mid] < key){
                low = mid+1;
            }else {
                high = mid-1;
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int arr[] = {1,2,3,3,4,4,4,4,4,5,6};
        System.out.println(getNumOfCount(arr,4));
        System.out.println();
    }
}

8.求数组中最小的K个数

排序,输出前k个,用一下堆排

package com.company;
/**
 * Description :
 * Created by Wanbo
 * Date :2021/7/20
 */
public class offer8 {
    public static void adjust(int[] arr, int start, int end){
        //start表示要调整树的根节点
        int tmp = arr[start];
        //找左右 孩子的最大值
        for(int i=2*start+1; i<=end; i=2*i+1){
            //判断是否有右孩子
            if(i+1 <= end && arr[i] < arr[i+1]){
                i++;//i指向左右孩子的最大值
            }
            if(arr[i] > tmp){
                //需要将arr[i]换到start位置
                arr[start] = arr[i];
                start = i; //更新start,保存当前最大孩子的下标
            }else{
                break;
            }
        }
        arr[start] = tmp;
    }

    public static void headSort(int[] arr){
        if(arr == null || arr.length == 0){
            return;
        }
        //i初始化为最后一个叶子节点所在子树的根节点
        //经过for循环之后发现当前序列所对应的堆是大根堆
        for(int i=(arr.length-1-1)/2; i>=0 ;i--){
            adjust(arr, i, arr.length-1);
        }
        for(int i=0; i<arr.length; i++){
            //相当于将根节点(待排序列的最大值)换到待排序列的最后
            int tmp = arr[0];
            arr[0] = arr[arr.length-1-i];
            arr[arr.length-1-i] = tmp;

            adjust(arr, 0, arr.length-1-i-1);
        }
    }
    public static void main(String[] args) {
        int[] arr = {2, 9, 10, 11, 29, 3, 6, 100, 50, 67, 30, 8};
        int k = 5;
        headSort(arr);
        for (int i=0; i<k; i++) {
            System.out.println(arr[i]);
        }
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

剑指Offer-面试算法题 的相关文章

随机推荐

  • SSM框架实战-搭建自己的个人博客2-UEditor编辑器的使用

    目录 UEditor 博客内容提交与展示功能测试 Controller开发 新增博客页面add ueditor jsp 博客详情界面detail jsp 博客新增和展示详情功能开发 博客存储 博客标题开发 标签POJO类 TagMapper
  • SSM框架实战-搭建自己的个人博客3-登录实现及前端界面设计

    目录 后台登录功能 前端页面 后端开发 前端界面设计 详情首页 js脚本 SSM整体设计 Dao层 Service层 Mapper xml Controller 子博文界面 部署至服务器 后台登录功能 登录页面 xff1a 用户名和密码 通
  • 超分辨率重建-PNSR与SSIM的计算(RGB、YUV和YCbCr互转)

    RGB YUV和YCbCr 自己复现的网络跑出来的模型进行预测的时候 xff0c 不知道为啥算出来的结果比论文中要低好多 不论scale factor为多少 xff0c 我算出来的结果均普遍低于论文中给出的 xff0c PSNR大概低个1
  • 如何写简历

    注意点 xff1a 篇幅 校招一页 社招二页 谨慎使用精通 精通 gt 熟悉 xff08 推荐使用 xff09 gt 掌握 xff08 推荐使用 xff09 gt 了解 xff08 推荐使用 xff09 拿不准的不要写在简历上 突出自己技能
  • SSM框架实战-搭建自己的个人博客4-文章管理与展示

    实现功能 主要实现上图所示的功能 xff0c 从数据库中查询到所有文章数据 xff0c 并进行显示如标题 xff0c 栏目等信息 xff0c 可以通过分类查询文章 xff0c 通过标签查询文章 xff0c 也可以通过搜索进行模糊查询 xff
  • Pytorch加载与保存模型(利用pth的参数更新h5预训练模型)

    前言 以前用Keras用惯了 xff0c fit和fit generator真的太好使了 xff0c 模型断电保存搞个checkpoint回调函数就行了 近期使用pytorch进行训练 xff0c 苦于没有类似的回调函数 xff0c 写完网
  • 如何用pyplot优雅的绘制loss,acc,miou,psnr变化曲线

    前言 TensorFlowBoard过于强大 xff0c 导致我对它依赖性很强 xff0c 今年转手使用pytorch进行开发 xff0c 本以为没了TensorFlowBoard xff0c 后来发现人家Tensorflow封装了个Ten
  • Pytorch实现CA,SA,SE注意力机制

    通道注意力CA class ChannelAttention nn Module def init self in planes ratio 61 16 super ChannelAttention self init self avg p
  • Python使用OpenCV按自定义帧率提取视频帧并保存

    在做室外语义分割 视觉导航与定位的时候 xff0c 通常会用对一个连续的视频帧进行测试 xff0c 除去常用数据集外 xff0c 也经常会自己制作一些数据集 xff0c 这个工具类可以按需求对视频进行分帧提取 xff0c 封装好了直接可以使
  • 悲观锁与乐观锁详解

    悲观锁 悲观锁顾名思义是从悲观的角度去思考问题 xff0c 解决问题 它总是会假设当前情况是最坏的情况 xff0c 在每次去拿数据的时候 xff0c 都会认为数据会被别人改变 xff0c 因此在每次进行拿数据操作的时候都会加锁 xff0c
  • 亚像素卷积网络(ESPCN)学习与Pytorch复现

    论文内容 论文地址 xff1a Real Time Single Image and Video Super Resolution Using an Efficient Sub Pixel Convolutional Neural Netw
  • Lock锁和ReentrantLock锁

    前言 JDK 1 5中提供的锁的接口java util concurrent locks Lock xff0c 其提供了一些ReentrantLock ReentrantReadWriteLock实现类 参考JDK文档 xff1a Java
  • 面试题--JVM垃圾回收及内存管理

    选择题 1 以下哪些内存区域属于 JVM 规范 xff1f xff08 xff09 A 方法区 B 实例变量 C 静态变量 D 程序计数器 E 虚拟机栈 正确答案 xff1a A D E 解析 xff1a Java虚拟机规范划分了七个内存区
  • Pytorch维度操作-unsqueeze、squeeze、view与permute

    view 在pytorch中view函数的作用为重构张量的维度 相当于numpy中resize 的功能 a 61 1 2 3 b 61 2 3 4 c 61 3 5 5 d 61 4 5 6 e 61 np array a b c d e
  • 长假余额为零!我用Python做了个中秋国庆双节拼图游戏

    点击上方 菜鸟学Python xff0c 选择 星标 公众号 重磅干货 xff0c 第一时间送达 今年的国庆长假非常长 xff0c 不知不觉已经余额为零 xff01 朋友圈很多晒出游的照片 xff0c 聚会的照片 xff0c 吃吃喝喝真舒服
  • Redis系列学习1-Redis安装启动与基础概念

    Remote Dictionary Server Redis 是一个由 Salvatore Sanfilippo 写的 key value 存储系统 xff0c 是跨平台的非关系型数据库 Redis 是一个开源的使用 ANSI C 语言编写
  • Redis系列学习2-五大类型(String,List,Hash,Set,ZSet)及其常规操作

    Redis的基本操作 Redis默认是有16个数据库 xff0c 默认使用的是第0个数据库 xff0c 可以通过select 切换数据库 xff0c Redis的命令大小写不敏感的 切换数据库 切换数据库 格式 xff1a select i
  • Redis系列学习3-geospatial地理空间

    geospatial 地理空间 可以用来实现定位 附近的人 打车APP上距离计算 距离的实现主要基于经纬度 xff0c 城市的经纬度查询 xff1a http www jsons cn lngcode geoadd 添加地址位置 格式 xf
  • 遗传算法求解TSP旅行商问题

    旅行商问题 旅行商问题 traveling salesman problem TSP 可描述为 已知N个城市之间的相互距离 现有一个商人必须遍访这N个城市 并且每个城市只能访问一次 最后又必须返回出发城市 如何安排他对这些城市的访问次序 使
  • 剑指Offer-面试算法题

    1 二分查找 xff08 递归与非递归实现 xff09 基本算法 xff0c 掌握好循环条件 package com company Description 二分查找 xff08 递归与非递归实现 xff09 Created by Wanb