《剑指offer》

本专题是分享剑指offer的一些题目,开始刷题计划。

二维数组的中的查找【https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqId=11154&ru=/exam/oj】

描述

在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

[

[1,2,8,9],

[2,4,9,12],

[4,7,10,13],

[6,8,11,15]

]

给定 target = 7,返回 true。

给定 target = 3,返回 false。

数据范围:矩阵的长宽满足 0≤�,�≤5000≤n,m≤500 , 矩阵中的值满足 0≤���≤1090≤val≤109

进阶:空间复杂度 �(1)O(1) ,时间复杂度 �(�+�)O(n+m)

示例1

输入:7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]

返回值 true

说明:存在7,返回true

示例2

输入:1,[[2]]

返回值 false

就是一个从右上角进行查找就可以了,当然也可以从左下角进行查找,这两个操作都是可以的。

代码:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param target int整型 
     * @param array int整型vector<vector<>> 
     * @return bool布尔型
     */
    bool Find(int target, vector<vector<int> >& array) {
        // write code here
        int i = 0;
        int j = array[0].size() - 1;
       
        while(i<array.size() && j>=0)
        {
             if(array[i][j] == target)
            {
                return true;
            }
            else if(array[i][j] > target)
            {
               j--;
            }
            else 
            {
                i++;
            }
        }
        return false;
    }
};

旋转数字的最小和https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=13&tqId=11159&ru=/exam/oj

描述

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:1≤�≤100001≤n≤10000,数组中任意元素的值: 0≤���≤100000≤val≤10000

要求:空间复杂度:�(1)O(1) ,时间复杂度:�(����)O(logn)

这类题目我们对此有三种解法,但是因为解题的效率是不同的,第一种解法就是暴力求解,遍历一遍数组,然后找出最小值,这样的时间复杂度是O(N)。

解法一

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int minNumberInRotateArray(vector<int>& nums) {
        // write code here
        int i = 0;
        int n = nums.size();
        int ret = nums[0];
        while(i < n)
        {
            if(ret > nums[i])
            {
                ret = nums[i];
            }
            i++;
        }
        return ret;
    }
};

虽然这种做法是能通过的,但是不符合我们对题目的要求,题目是要求一个O(logN)的写法,这个是不满足的,解法二是一个类似双指针的做法

解法二

双指针

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型vector
     * @return int整型
     */
    int minNumberInRotateArray(vector<int>& nums) {
        // write code here
        int left = 0;
        int right = 1;
        int n = nums.size();
        while(right < n)
        {
            if(nums[left] > nums[right])
            {
                return nums[right];
            }
            right++;
            left++;
        }
        if(nums[0] < nums[n - 1])
        {
            return nums[0];
        }
        return 0;
    }
};

但是这个是存在随机性的,因为最坏的情况的时候,时间复杂度还是O(N),所以这题的解法如果要达到O(logN)就是一个二分查找,这里分享两种写法。

二分查找

写法一

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int minNumberInRotateArray(vector<int>& nums) {
        // write code here
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        if(nums[left] < nums[right])
        {
            return nums[left];
        }
        while(left < right)
        {
            if(right - left == 1)
            {
                mid = right;
                break;
            }

            mid = left + (right - left ) / 2;
            if(nums[mid] == nums[left] && nums[right] == nums[mid])
            {
                int ret = nums[left];
                for(int i = left + 1; i < right; i++)
                {
                    if(ret > nums[i])
                    {
                        ret = nums[i];
                    }
                }
                return ret;
            }
            if(nums[mid] >= nums[left])
            {
                left = mid;
            }
            else  
            {
                right = mid;
            }
        }
        return nums[mid];
    }
};

但是这个其实感觉也不完全是一个二分查找,因为如果数据全部是一样的时候就不是一个完整的二分查找了,但是如果数据不同的时候就是一个完整的二分查找了。

解法二

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int minNumberInRotateArray(vector<int>& nums) {
        // write code here
        int left = 0;
        int right = nums.size() - 1;
        while(left < right)
        {
            if(nums[left] < nums[right])
            {
                return nums[left];
            }
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[right])
            {
                left = mid+1;
            }
            else if(nums[mid] < nums[right])
            {
                right = mid;
            }
            else  
            {
                right--;
                //或者写成left++目的其实就是排除一些相同的数字
            }

        }
        return nums[left];
    }
};

本人推荐解法二,这个比较是符合二分查找的,但是其实二分查找是有一些模板的,后面会在算法专题更新模板。

调整奇数位置到偶数位置之前

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

思路一其实就是可以用双指针的方法,就是从左边和右边一并开始,然后遇到左边找奇数,右边找偶数,进行交换就行了。

思路2

找到奇数然后进行保存,将偶数位置整体往后移动,移动的时候需要注意的一点就是我们之前调整过的奇数是不需要进行调整的,而且调整的位置是当前的奇数开始往前调的。

代码

public class Solution {
    public void reOrderArray(int [] array) {
        //相对位置不变,稳定性
        //插入排序的思想
        int m = array.length;
        int k = 0;//记录已经摆好位置的奇数的个数
        for (int i = 0; i < m; i++) {
            if (array[i] % 2 == 1) {
                int j = i;
                while (j > k) {//j >= k+1
                    int tmp = array[j];
                    array[j] = array[j-1];
                    array[j-1] = tmp;
                    j--;
                }
                k++;
            }
        }
    }
}

三题分享完毕,明天继续。

相关推荐
van叶~15 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法16 分钟前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
云卓SKYDROID30 分钟前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香1 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童1 小时前
双指针算法习题解答
算法
想要打 Acm 的小周同学呀1 小时前
LRU缓存算法
java·算法·缓存
劲夫学编程2 小时前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪2 小时前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_4 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师6 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim