剑指Offer之Java算法习题精讲数组查找与字符串交集

剑指Offer之Java算法习题精讲 - 数组查找与字符串交集

一、本章介绍

本章将会对“剑指Offer”系列书籍中有关数组查找与字符串交集的核心算法习题进行总结和分析。我们将会结合具体的算法样例进行讲解,并且会针对其中涉及到的算法思想与编程技巧进行加深细致的探讨。

二、数组查找

1. 二维数组中的查找

题目描述:

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完整实现一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数,并返回一个 boolean 值。

算法思路:

从矩阵右上角的元素开始,如果该元素等于目标值,则返回 true;如果该元素大于目标值,则剔除该元素所在列;如果该元素小于目标值,则剔除该元素所在行。以此类推,直到找到目标值或到达矩阵边界。

代码示例:

public static boolean findInPartiallySortedMatrix(int[][] matrix, int target) {
    if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
        return false;
    }
    int row = 0;
    int col = matrix[0].length - 1;
    while (row < matrix.length && col >= 0) {
        if (matrix[row][col] == target) {
            return true;
        } else if (matrix[row][col] > target) {
            col--;
        } else {
            row++;
        }
    }
    return false;
}

2. 旋转数组的最小数字

题目描述:

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为旋转。求一个非递减数组的旋转数组的最小数字。例如,数组 {3,4,5,1,2} 为 {1,2,3,4,5} 的一个旋转,该数组的最小值为1。

算法思路:

考虑使用二分查找算法。对于一个排序的数组,使用二分查找算法的时间复杂度为 O(log n)。但是此处的数组是一个旋转数组,因此需要更改查找算法的判断条件。对于一个数组,以最后一个元素为分界点将其分为两个有序的子数组,旋转数组的最小数字即为后半部分的首个元素。每一次查找后,可以通过比较中间元素与区间边界元素的大小来确定需要继续加载左半部分还是右半部分。

代码示例:

public static int minNumberInRotateArray(int[] array) {
    if (array == null || array.length == 0) {
        return 0;
    }
    int left = 0;
    int right = array.length - 1;
    while (left < right) {
        int mid = (left + right) / 2;
        if (array[mid] > array[right]) {
            left = mid + 1;
        } else if (array[mid] == array[right]) {
            right--;
        } else {
            right = mid;
        }
    }
    return array[left];
}

三、字符串交集

1. 字符串排列

题目描述:

输入一个字符串,打印出该字符串中字符的所有排列。例如,输入字符串 abcd,则输出由字符 a、b、c、d 所能排列出来的所有字符串:abcd、abdc、acbd、acdb、adbc、adcb、bacd、badc、bcad、bcda、bdac、bdca、cabd、cadb、cbad、cbda、cdab、cdba、dabc、dacb、dbac、dbca、dcab、dcba。

算法思路:

本题可以使用递归算法解决。固定第一个字符,对剩余字符进行排列。依次枚举第一个字符,再求后面的字符串的排列。当字符串只有一个字符时,其返回值为该字符本身。

代码示例:

public static ArrayList<String> permutation(String string) {
    ArrayList<String> result = new ArrayList<>();
    if (string == null || string.length() == 0) {
        return result;
    }
    char[] chars = string.toCharArray();
    recursion(result, chars, 0);
    Collections.sort(result); // 排序
    return result;
}

private static void recursion(ArrayList<String> result, char[] chars, int i) {
    if (i == chars.length - 1) {
        result.add(String.valueOf(chars));
    } else {
        Set<Character> set = new HashSet<>();
        for (int j = i; j < chars.length; j++) {
            if (!set.contains(chars[j])) {
                set.add(chars[j]);
                swap(chars, i, j);
                recursion(result, chars, i + 1);
                swap(chars, i, j);
            }
        }
    }
}

private static void swap(char[] chars, int i, int j) {
    char temp = chars[i];
    chars[i] = chars[j];
    chars[j] = temp;
}

2. 字符串转换成整数

题目描述:

将一个字符串转换成一个整数,该字符串一定表示一个正整数,例如输入字符串 "345",则输出数字 345。

算法思路:

本题可以使用从左到右遍历字符串,累加每个字符对应的数字,最终得到该字符串所表示的整数的值。需要注意参数合法性边界和数字溢出问题。

代码示例:

public static int strToInt(String str) {
    if (str == null || str.length() == 0) {
        return 0;
    }
    int sign = 1; // 标记正负
    int sum = 0; // 累加和
    int i = 0;
    char[] chars = str.toCharArray();
    if (chars[0] == '+' || chars[0] == '-') {
        if (chars[0] == '-') {
            sign = -1;
        }
        i++;
    }
    for (; i < chars.length; i++) {
        // 检查字符是否合法
        if (chars[i] < '0' || chars[i] > '9') {
            return 0;
        }
        // 检查数字是否溢出
        if (sum > Integer.MAX_VALUE / 10 || (sum == Integer.MAX_VALUE / 10 && (chars[i] - '0') > Integer.MAX_VALUE % 10)) {
            return 0;
        }
        sum = sum * 10 + (chars[i] - '0');
    }
    return sign * sum;
}

四、小结

通过本章的学习,我们不仅对数组查找和字符串交集的核心算法有了更为深入的认识,同时也熟悉了在Java中实现各种不同类型算法的代码操作技巧。我们希望这些经验能够为读者在今后的编程实践中提供帮助与指导。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:剑指Offer之Java算法习题精讲数组查找与字符串交集 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • java使用反射给对象属性赋值的两种方法

    当我们需要在运行时使用Java代码来处理类,或者动态地访问和修改类的成员时,反射成为一种非常重要的机制。其中一个反射的应用场景就是给对象属性赋值,在此介绍两种方法。 方法一:使用Class类的getMethod()和setAccessible()方法 首先,需要获得指定的方法,然后再反射到对象上进行调用。下面是一个示例,通过这种方法动态设置User对象的na…

    Java 2023年5月26日
    00
  • JSP 自定义标签第1/3页

    接下来我将为您详细讲解 JSP 自定义标签的完整攻略。 什么是 JSP 自定义标签? JSP 自定义标签(JSP Custom Tag)是一种 JSP 的扩展机制,可以将页面的展现与页面逻辑分离开来。自定义标签通过定义自己的语法可以将一些 Java 代码片段封装到自定义标签中,使得这些功能可以在 JSP 页面中通过 XML 标签来调用使用。 JSP 自定义标…

    Java 2023年6月15日
    00
  • Spring Security权限控制的实现接口

    Spring Security 是一个强大的安全框架,提供了多种方式来保证应用程序的安全性。其中最重要的就是权限控制,这也是 Spring Security 最常用的功能。 Spring Security 权限控制基于接口进行实现,主要有以下几个接口: UserDetailsService 接口:该接口用于查询用户信息,包括用户名、密码、权限等。实现该接口一…

    Java 2023年5月20日
    00
  • 基于JavaMail的Java实现简单邮件发送功能

    下面是详细攻略: JavaMail介绍 JavaMail是一种在Java平台上发送和接收电子邮件的API。JavaMail被设计用于打理所有与邮件相关的任务,包括发送、接收、查看或删除邮件等操作。JavaMail的主要功能如下: 连接邮件服务器 发送邮件 接收邮件 删除邮件 Java实现简单邮件发送功能 在Java中要使用JavaMail实现邮件发送功能,需…

    Java 2023年5月18日
    00
  • Java入门基础之常规的命名方法和变量的值及其引用

    Java入门基础之常规的命名方法和变量的值及其引用 Java 是一种面向对象的编程语言,命名方法和变量的值及其引用都是 Java 程序中非常重要的基础概念。正确使用命名方法和变量值及其引用,可以帮助我们编写出更加可读性强、易于维护的 Java 代码。 命名方法 命名方法在编程语言中属于相对固定的规范。在 Java 中,命名方法需要遵循以下几个基本规则: 命名…

    Java 2023年5月26日
    00
  • 全面解析Hibernate关联操作、查询操作、高级特性、并发处理机制

    全面解析Hibernate关联操作、查询操作、高级特性、并发处理机制 Hibernate是一个流行的Java对象关系映射框架,它可以将Java对象映射到数据库表中。本文将全面介绍Hibernate的四个主要方面:关联操作、查询操作、高级特性和并发处理机制。 关联操作 Hibernate支持多种关联操作,包括一对一、一对多、多对一和多对多关联。下面是一对多关联…

    Java 2023年5月19日
    00
  • JSP一句话后门

    JSP一句话后门是指一种通过JSP页面实现的远程执行命令的后门。攻击者通过该后门可以远程控制服务器,操作服务器上的文件、数据库等敏感信息。下面是该后门的完整攻略: 1. 获取受害者的管理员权限 攻击者需要先获取目标服务器的管理员权限,这一步可以通过常见的漏洞进行攻击,例如未授权访问、SQL注入等。攻击者可以通过获取管理员权限,修改或上传JSP文件。 2. 编…

    Java 2023年6月15日
    00
  • SpringSecurity实现动态加载权限信息的方法

    实现动态加载权限信息的方法是Spring Security中非常重要的一部分,可以根据用户的动态信息进行精确的授权管理。下面是详细的实现攻略。 1. 编写权限信息源的代码 Spring Security中支持自定义的权限信息源,我们需要实现 org.springframework.security.access.vote.RoleVoter 接口并提供动态的…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部