【力扣题型总结及模版】剑指offer 1 - 数组与字符串

题型总结

题目概述做法关键词
二维数组中的查找在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。从右上角开始,比目标大就往左走,比目标小就往下走数组遍历
打印从 1 到最大的 n 位数输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。1⃣️ 对[1 2 3 4 5 6 7 8 9]乘以10再加上这个数组,最前面加上0开头的,需要多少位就循环多少次 2⃣️ 用字符串拼接,最后一位从0到9递增 ⚠️可能考察大数计算问题数组遍历
构建乘积数组给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。分成上下三角矩阵,维护一个tmp从三角尖乘到底部数组遍历
顺时针打印矩阵输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。定义上下左右边界,循环遍历整个数组,循环中再嵌套四个循环,分别是从左至右,从上至下,从右至左,从下至上这几个方向,按照题意将整个数组遍历完成,控制好边界。循环+注意边界
替换空格请实现一个函数,把字符串 s 中的每个空格替换成"%20"StringBuilder, s.charAt遍历,不是空格就append,是空格就换成“%20”字符串遍历
II. 左旋转字符串字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。在原字符串处从需要反转的位置 n 开始向后遍历,并保存到结果字符串中,然后再从原字符串的初始位置遍历到位置 n,继续添加到结果字符串字符串遍历或substring拼接
扑克牌中的顺子从扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这 5 张牌是不是连续的。2 ~ 10 为数字本身,A 为 1,J 为 11,Q 为 12,K 为 13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。需要对数组升序排序;如果数组中有重复数据,则返回 false;令 minVal 为不包含大小王的最小值,如果 maxVal-minVal > 5,则返回 false数组排序Arrays.sort()
旋转数组的最小数字把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。二分查找,判断条件为mid是否大于right排序-二分
把数组排成最小的数输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。改变快排中的规则:若拼接字符串x+y>y+x, 则数值x > y🌟排序-快排
调整数组顺序使奇数位于偶数前面输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。首先指定前指针 start 和后指针 end,然后前指针定位偶数,后指针定位奇数,定位到之后将两个值互换,直到数组遍历完成双指针
和为 s 的两个数字输入一个递增排序的数组和一个数字 s,在数组中查找两个数,使得它们的和正好是 s。如果有多对数字的和等于 s,则输出任意一对即可。如果没有排序要先排序,双指针,大了右指针–,小了左指针–双指针
I. 翻转单词顺序输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串 "I am a student. ",则输出 “student. a am I”。先将开头和结尾处多余的空格去掉,从后向前遍历,通过前后指针锁定单词,跳过中间空格,最终将整个句子中的单词反转双指针
和为 s 的连续正数序列输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)使用滑动窗口,设立左右指针,从开始位置维护一个子数组作为窗口,判断该窗口是否求和为 target,如果是则将结果加入,如果小于 target 则窗口右移,大于 target 则窗口左移🌟滑动窗口
数组中出现次数超过一半的数字(众数)数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。1⃣️ 数组排序->nums[mid] O(nlogn) 2⃣️ 哈希计数->遍历 O(n) 3⃣️ 摩尔投票:遍历 nums 数组,使用 count 进行计数,记录当前出现的数字为 cur,如果遍历到的 num 与 cur 相等,则 count 自增,否则自减,当其减为 0 时则将 cur 修改为当前遍历的 num,通过增减抵消的方式,最终达到剩下的数字是结果的效果,时间复杂度为O(n)🌟摩尔投票
I. 在排序数组中查找数字统计一个数字在排序数组中出现的次数。(如果数组没排序要先排序) 二分查找到target和target-1的右边界,两者相减即可二分查找
0~n-1中缺失的数字一个长度为 n-1 的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围 0~n-1 之内。在范围 0~n-1 内的 n 个数字中有且只有一个数字不在该数组中,请找出这个数字。缺失的数字等于 “右子数组的首位元素” 对应的索引,因此考虑使用二分法查找 “右子数组的首位元素”。左子数组: nums[i] == i 右子数组: nums[i] != i二分查找
把字符串转换成整数写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。⭕️ 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。⭕️ 当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。⭕️ 该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。⭕️ 注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。⭕️ 在任何情况下,若函数不能进行有效的转换时,请返回 0。 说明:假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为  [−231,  231 − 1]。如果数值超过这个范围,请返回  INT_MAX (231 − 1) 或  INT_MIN (−231) 。trim()去空格 -> 判断正负号 -> 字符转数字c-'0'-> 处理非数字情况 -> 大数处理,res和Integer.MAX_VALUE/10比较,判断是否越界,如果超过 2147483647,直接返回 ⚠️不要用Integer.MIN_VALUE,他不能直接*-1变成-MIN_VALUE大数处理

模板

二分法

  1. 定义 int mid = left + (right - left)/2;(防止大数溢出)
  2. 左右为数组左右
  3. 当左指针小于等于右指针时->if(判断向左右找的条件)->下一步向左找 left = mid + 1;,向右找right = mid - 1;

快排

快排解释-CSDN

  1. 找基准元素:传入的数组第一位作为基准元素,首尾双指针,(从大到小排序)左指针找比基准元素小的,右指针找比基准元素大的,交换位置,最后返回分割点的index。
  2. 递归调用,当左<右时,对左边/右边数组快排。
public class QuickSort {
    private static void quickSort(int[] array, int startIndex, int endIndex) {
        if (startIndex < endIndex) {
            // 找基准元素
            int baseIndex = divide(array, startIndex, endIndex);
            // 递归调用,对分隔后的左边数组快速排序
            quickSort(array, startIndex, baseIndex - 1);
            // 递归调用,对分隔后的右边数组快速排序
            quickSort(array, baseIndex + 1, endIndex);
        } else {
            return;
        }
    }

    /**
     * 利用双边循环法分隔数组
     *
     * @param array      需要排序的数组
     * @param startIndex 数组的开始下标
     * @param endIndex   数组的结束下标
     * @return 返回分隔点所在的位置
     */
    private static int divide(int[] array, int startIndex, int endIndex) {
        // 用数组的第一个元素作为起始元素
        int base = array[startIndex];
        int i = startIndex;
        int j = endIndex;
        while (i != j) {
            // 从右向左寻找第一个小于基准数的值
            while (i < j && array[j] > base) {
                j--;
            }
            // 从左向右寻找第一个大于基准数的值
            while (i < j && array[i] <= base) {
                i++;
            }
            // 交换位置
            if (i < j) {
                swap(array, i, j);
            }
        }

        // 指针i 与指针j 相遇,把重合点的元素与基准元素交换位置
        array[startIndex] = array[i];
        array[i] = base;

        // 返回分隔点所在的位置
        return i;
    }

    // 交换i 与 j 位置的值
    private static void swap(int[] array, int i, int j) {
        int temp;
        temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

滑动窗口

class Solution {
    public int[][] findContinuousSequence(int target) {
        int left = 1;
        int right = 2;
        List<int[]> res = new ArrayList<>();

        while (left < right) {
            int sum = (left + right) * (right - left + 1) / 2;
            if (sum == target){
                int[] arr = new int[right - left + 1];
                for (int k = left; k <= right; k++) {
                    arr[k - left] = k;
                }
                res.add(arr);
                left++;
            }
            else if (sum < target) {
                right++;
            }
            else {
                left++;
            }
        }

        return res.toArray(new int[res.size()][]);
    }
}

例题答案

顺时针打印矩阵

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0) return new int[0];
        int left = 0, right = matrix[0].length - 1, top = 0, bottom = matrix.length - 1, x = 0;
        int[] res = new int[(right + 1) * (bottom + 1)];
        while(true) {
            for(int i = left; i <= right; i++) res[x++] = matrix[top][i];
            if(++top > bottom) break;
            for(int i = top; i <= bottom; i++) res[x++] = matrix[i][right];
            if(left > --right) break;
            for(int i = right; i >= left; i--) res[x++] = matrix[bottom][i];
            if(top > --bottom) break;
            for(int i = bottom; i >= top; i--) res[x++] = matrix[i][left];
            if(++left > right) break;
        }
        return res;
    }
}

摩尔投票

class Solution {
    public int majorityElement(int[] nums) {
        int cur = 0;
        int count = 0;
        for(int num : nums){
            if(count == 0) {
                cur = num;
            }
            if(num == cur) {
                count++;
            } else {
                count--;
            }
        }
        return cur;
    }
}

快排

    public String minNumber(int[] nums) {
        String[] strs = new String[nums.length];
        for (int i = 0; i < nums.length; i++) {
            strs[i] = String.valueOf(nums[i]);
        }
        quickSort(strs, 0, strs.length - 1);
        StringBuilder res = new StringBuilder();
        for (String s : strs)
            res.append(s);
        return res.toString();
    }

    public void quickSort(String[] strs, int low, int high) {
        if (low < high) {
            int middle = getMiddle(strs, low, high);
            quickSort(strs, low, middle - 1);
            quickSort(strs, middle + 1, high);
        }
    }

    public int getMiddle(String[] strs, int low, int high) {
        //数组的第一个数为基准元素
        String temp = strs[low];
        while (low < high) {
            //从后向前找比基准小的数
            while (low < high && (strs[high] + temp).compareTo(temp + strs[high]) >= 0)
                high--;
            //把比基准小的数移到低端
            strs[low] = strs[high];
            //从前向后找比基准大的数
            while (low < high && (strs[low] + temp).compareTo(temp + strs[low]) <= 0)
                low++;
            //把比基准大的数移到高端
            strs[high] = strs[low];
        }
        strs[low] = temp;
        return low;
    }

大数处理

class Solution {
    public int strToInt(String str) {
        char[] c = str.trim().toCharArray();
        if(c.length == 0) return 0;
        int res = 0, boundry = Integer.MAX_VALUE / 10;
        int start = 1, sign = 1;
        if(c[0] == '-') sign = -1;
        else if(c[0] != '+') start = 0;
        for(int i = start; i < c.length; i++) {
            if(c[i] < '0' || c[i] > '9') break;
            if(res > boundry || res == boundry && c[i] > '7') return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res * 10 + (c[i] - '0');
        }
        return sign * res;
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值