带你刷算法——数组/字符串的完全掌握(一)

这篇具有很好参考价值的文章主要介绍了带你刷算法——数组/字符串的完全掌握(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法
「作者主页」:雪碧有白泡泡
「个人网站」:雪碧的个人网站
「推荐专栏」

java一站式服务
前端炫酷代码分享
uniapp-从构建到提升
从0到英雄,vue成神之路
解决算法,一个专栏就够了 架构咱们从0说
★ 数据流通的精妙之道★

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

1.合并两个有序数组

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2
中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m
个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 :

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6]
,其中斜体加粗标注的为 nums1 中的元素。 示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0 输出:[1] 解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。 示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1 输出:[1] 解释:需要合并的数组是 [] 和 [1]
。 合并结果是 [1] 。 注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0
仅仅是为了确保合并结果可以顺利存放到 nums1 中。

提示:

  • nums1.length == m + n nums2.length == n 0 <= m,
  • n <= 200 1 <= m + n <=200 -109 <= nums1[i],
  • nums2[j] <= 109

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:暴力

import java.util.Arrays;

public class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        // 将 nums2 合并到 nums1 的后面
        for (int i = 0; i < n; ++i) {
            nums1[m + i] = nums2[i];
        }
        
        // 对合并后的数组进行排序
        Arrays.sort(nums1);
    }
}

这段代码的主要思路是将数组nums2合并到数组nums1的后面,然后对合并后的数组进行排序。

首先,通过一个循环将nums2中的元素逐个复制到nums1的末尾。循环变量i从0开始,每次迭代将nums2[i]赋值给nums1[m + i],其中mnums1中已有元素的数量。这样就完成了合并的过程。

接下来,使用Arrays.sort()方法对合并后的数组nums1进行升序排序。这个方法会自动对数组中的元素进行排序,使得最终的数组呈现升序排列。

需要注意的是,这种实现方式会修改原始的nums1数组。如果不想修改原始数组,可以先创建一个临时数组,并将nums1复制到临时数组中,然后在临时数组上进行合并和排序操作。

思路二:双指针

public class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m - 1;
        int j = n - 1;
        int k = m + n - 1;

        while (i >= 0 && j >= 0) {
            if (nums1[i] > nums2[j]) {
                nums1[k--] = nums1[i--];
            } else {
                nums1[k--] = nums2[j--];
            }
        }

        while (j >= 0) {
            nums1[k--] = nums2[j--];
        }
    }
}

这段代码实现的思路是将两个有序数组nums1nums2合并为一个有序数组,并将结果存储在nums1中。

首先,定义三个指针ijki指向nums1中的最后一个元素(有效元素),j指向nums2中的最后一个元素,k指向合并后的结果应该存储的位置。

然后,通过一个循环遍历两个数组,从后往前比较nums1[i]nums2[j]的大小。如果nums1[i]大于nums2[j],就将nums1[i]放入合并后的结果数组的末尾(即nums1[k]),并将ik分别减一。如果nums1[i]小于等于nums2[j],就将nums2[j]放入合并后的结果数组的末尾,并将jk分别减一。重复这个过程直到其中一个数组遍历完。

最后,如果nums2中还有剩余元素(即j >= 0),则将剩余元素依次放入合并后的结果数组的末尾。

这种方式不需要创建额外的数组,只需要在原始的nums1数组上进行操作,节省了空间复杂度。同时,由于两个数组都是有序的,所以可以通过从后往前比较的方式,避免了频繁移动元素和插入操作,提高了效率。

2.移除元素

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。 for
(int i = 0; i < len; i++) {
print(nums[i]); }

示例 1:

输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2] 解释:函数应该返回新的长度 2, 并且
nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums =
[2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2 输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0,
4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示:

0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:暴力法

public class Solution {
    public int removeElement(int[] nums, int val) {
        int i = 0;
        int n = nums.length;

        while (i < n) { // 当前指针位置小于数组长度时进行遍历
            if (nums[i] == val) { // 如果当前元素等于 val,则将最后一个元素复制到当前位置
                nums[i] = nums[n - 1];
                n--; // 数组长度减少1
            } else {
                i++; // 否则,移动指针到下一个位置
            }
        }

        return n; // 返回新的数组长度
    }
}

这段代码的主要思路是移除数组nums中所有值为val的元素,并返回新的数组长度。

首先,定义两个指针ini表示当前遍历到的位置,n表示当前有效元素的数量,即数组的长度。

然后,通过一个循环遍历数组nums。在每次迭代中,首先检查当前位置nums[i]是否等于目标值val。如果相等,则将最后一个元素nums[n - 1]复制到当前位置nums[i]上,同时将数组长度n减1,表示有效元素的数量减少了1。这样就实现了将目标值移到数组末尾的操作。

如果当前位置nums[i]不等于目标值val,则直接将指针i向后移动一位,继续遍历下一个元素。

重复这个过程直到遍历完整个数组。最终,数组中所有值为val的元素都被移动到了末尾,并且数组的长度变为n

最后,返回新的数组长度n作为结果。

这种方法通过双指针操作,避免了频繁的元素搬移,提高了效率。由于题目并未要求删除特定的元素,只需要将目标值移到数组末尾,并返回新的数组长度,所以元素的相对顺序并不重要。

优化
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length;
        while (left < right) {
            if (nums[left] == val) {
                nums[left] = nums[right - 1];
                right--;
            } else {
                left++;
            }
        }
        return left;
    }
}


这段代码的主要思路与之前给出的代码类似,都是移除数组nums中所有值为val的元素,并返回新的数组长度。

首先,定义两个指针leftrightleft表示当前遍历到的位置,right表示有效元素的右边界,初始时为数组的长度。

然后,通过一个循环遍历数组nums。在每次迭代中,首先检查当前位置nums[left]是否等于目标值val。如果相等,则将最后一个元素nums[right - 1]复制到当前位置nums[left]上,同时将有效元素的右边界right减1,表示有效元素的数量减少了1。这样就实现了将目标值移到数组末尾的操作。

如果当前位置nums[left]不等于目标值val,则直接将左指针left向后移动一位,继续遍历下一个元素。

重复这个过程直到左指针left与右指针right相遇,即遍历完整个数组。最终,数组中所有值为val的元素都被移动到了末尾,并且左指针left所指示的位置即为新的数组长度。

最后,返回左指针left作为结果。

这种方法同样通过双指针操作,避免了频繁的元素搬移,提高了效率。与前一个代码不同的是,这里使用了左指针和右指针,在处理元素的替换时更加简洁。

3.删除有序数组中的重复项

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序
应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。 返回 k 。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过。

示例 1:

输入:nums = [1,1,2] 输出:2, nums = [1,2,_] 解释:函数应该返回新的长度 2 ,并且原数组 nums
的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4] 输出:5, nums = [0,1,2,3,4] 解释:函数应该返回新的长度
5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

1 <= nums.length <= 3 * 104 -104 <= nums[i] <= 104 nums 已按 升序 排列

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:暴力法

class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        if (n == 0) {
            return 0;
        }
        int k = 1;  // 记录唯一元素的数量
        for (int i = 1; i < n; i++) {
            if (nums[i] != nums[i-1]) {  // 当前元素与前一个元素不相等
                nums[k] = nums[i];  // 将当前元素移动到正确位置
                k++;
            }
        }
        return k;
    }
}

这段代码使用一个指针 k 来记录唯一元素的数量。初始化 k 为 1,表示第一个元素肯定是唯一的。

然后从数组的第二个元素开始遍历,如果当前元素与前一个元素不相等,则将当前元素移动到正确的位置,即数组的第 k 个位置,并将 k 自增 1。

最后返回 k,即为删除重复元素后的新数组长度。

请注意,这段代码要求输入的数组 nums 是升序排列的,才能正确删除重复元素。

思路二:快慢指针

class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        if (n == 0) {
            return 0;
        }
        int fast = 1, slow = 1;
        while (fast < n) {
            if (nums[fast] != nums[fast - 1]) {
                nums[slow] = nums[fast];
                ++slow;
            }
            ++fast;
        }
        return slow;
    }
}

这段代码的主要思路是使用双指针方法来移除已排序数组中的重复元素,并返回修改后的数组长度。

具体步骤如下:

  1. 首先,获取数组的长度n。
  2. 如果数组为空(即n为0),则直接返回0,因为没有重复元素需要移除。
  3. 初始化两个指针:fast和slow,初始值都为1。其中,fast指针用于遍历数组,从第二个元素开始;slow指针用于记录最后一个非重复元素的位置。
  4. 进入循环,遍历数组直到fast指针达到数组末尾。
  5. 在每次迭代中,比较当前fast指针位置的元素与其前一个元素是否相等。如果不相等,说明找到了一个新的不重复元素。
  6. 将该新的不重复元素赋值给slow指针所在的位置,覆盖掉原有的重复元素。
  7. slow指针向后移动一位,指向下一个可能的不重复元素的位置。
  8. fast指针也向后移动一位,继续遍历数组。
  9. 循环结束后,返回slow指针的值,它表示修改后的数组的长度。由于slow指针记录的是最后一个非重复元素的位置,所以长度为slow表示没有重复元素的子数组的长度。

总结起来,这段代码通过快慢指针的方式,在遍历数组过程中,将不重复的元素移动到数组的前面,并且记录下不重复子数组的长度。最终实现了原地修改数组,去除重复元素的目的。

4.多数元素

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:nums = [3,2,3] 输出:3

示例 2:

输入:nums = [2,2,1,1,1,2,2] 输出:2

提示:

  • n == nums.length
  • 1 <= n <= 5 * 104
  • -109 <= nums[i] <= 109

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:暴力解法

暴力解法是通过遍历数组并统计每个元素的出现次数,然后判断是否满足大于 n/2 的条件。以下是一个使用暴力解法的示例代码:

public class Solution {
    public int majorityElement(int[] nums) {
        int n = nums.length;
        for (int num : nums) {
            int count = 0;
            for (int i = 0; i < n; i++) {
                if (nums[i] == num) {
                    count++;
                }
            }
            if (count > n / 2) {
                return num;
            }
        }
        return -1; // 如果输入的数组不符合题目要求,没有多数元素,则返回一个特定的值(例如 -1)
    }
}

上述代码中,我们使用两层循环来遍历整个数组。外层循环用于遍历每个元素,内层循环用于统计该元素在数组中出现的次数。如果某个元素的出现次数大于 n/2,则返回该元素作为多数元素。

请注意,上述代码并没有对输入数组进行非空判断或检查是否存在多数元素。根据题目描述,假设输入数组是非空的,并且总是存在多数元素。但在实际应用中,需要增加相应的逻辑来处理这些边界情况。

思路二:复杂度为O(1)随机化法

class Solution {
    private int randRange(Random rand, int min, int max) {
        return rand.nextInt(max - min) + min;
    }

    private int countOccurences(int[] nums, int num) {
        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == num) {
                count++;
            }
        }
        return count;
    }

    public int majorityElement(int[] nums) {
        Random rand = new Random();

        int majorityCount = nums.length / 2;

        while (true) {
            int candidate = nums[randRange(rand, 0, nums.length)];
            if (countOccurences(nums, candidate) > majorityCount) {
                return candidate;
            }
        }
    }
}

这段代码的目标是找出给定整数数组中的主要元素(即出现次数超过一半的元素)。下面是该代码的思路:

  1. randRange 方法中,使用 Random 类生成一个介于 minmax 之间的随机整数。
  2. countOccurences 方法用于计算在给定数组 nums 中等于 num 的元素个数。
  3. majorityElement 方法是主要的方法,它首先创建了一个 Random 对象 rand
  4. 然后根据数组长度计算出了主要元素的最小出现次数 majorityCount,即数组长度的一半。
  5. 使用一个无限循环,在每次迭代中选择一个随机索引,并将对应的元素赋值给 candidate
  6. 然后通过调用 countOccurences 方法来计算 candidate 在数组中的出现次数。
  7. 如果 candidate 的出现次数超过了 majorityCount,则返回 candidate,因为它是主要元素。
  8. 如果没有找到主要元素,则会继续循环直到找到为止。

需要注意的是,由于数组中一定存在一个主要元素,所以这个循环一定会终止并返回结果。但是,这种方法的时间复杂度可能很高,因为在每次迭代中需要遍历整个数组来计算出现次数。在某些情况下,这可能导致性能问题。

5.买卖股票的最佳时机

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4] 输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 =6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1] 输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 104

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:暴力法

暴力解法可以通过考虑每一天作为买入点,然后在之后的每一天作为卖出点,计算利润并找到最大值。以下是使用暴力解法的Java代码示例:

class Solution {
    public int maxProfit(int[] prices) {
        int maxProfit = 0;
        
        for (int i = 0; i < prices.length - 1; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                int profit = prices[j] - prices[i];
                if (profit > maxProfit) {
                    maxProfit = profit;
                }
            }
        }
        
        return maxProfit;
    }
}

上述代码中,我们使用两个循环嵌套来遍历所有可能的买入和卖出点组合。对于每个组合,我们计算卖出价格减去买入价格得到的利润,并将其与当前的最大利润进行比较。如果新计算的利润更大,则更新最大利润。

然后返回最大利润作为结果。这种暴力解法的时间复杂度为 O(n^2),其中 n 是数组的长度。
带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

思路二:一次遍历

public class Solution {
    public int maxProfit(int prices[]) {
        int minprice = Integer.MAX_VALUE;
        int maxprofit = 0;
        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < minprice) {
                minprice = prices[i];
            } else if (prices[i] - minprice > maxprofit) {
                maxprofit = prices[i] - minprice;
            }
        }
        return maxprofit;
    }
}
  1. 初始化minprice为整数的最大值,maxprofit为0。minprice用于记录迄今为止最低的股票价格,maxprofit用于记录迄今为止最大的利润。

  2. 遍历给定的股票价格数组prices,从索引0开始到数组末尾。

  3. 对于每个价格prices[i],首先检查它是否比当前的minprice更低。如果是,则更新minpriceprices[i],因为我们找到了一个更低的购买价格。

  4. 如果prices[i]不是比当前的minprice更低,那么我们计算以当前价格卖出时的利润。将prices[i] - minprice与当前的maxprofit进行比较,如果大于maxprofit,则更新maxprofitprices[i] - minprice,因为我们找到了一个更大的利润。

  5. 完成遍历后,maxprofit中存储的就是股票买卖的最大利润。

该算法的时间复杂度为O(n),其中n是股票价格数组的长度。

6.罗马数字转整数

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符 数值

I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
  • 给定一个罗马数字,将其转换成整数。

示例

输入: s = “III” 输出: 3

输入: s = “IV” 输出: 4

输入: s = “IX” 输出: 9 :

输入: s = “LVIII” 输出: 58 解释: L = 50, V= 5, III = 3.

输入: s = “MCMXCIV” 输出: 1994 解释: M = 1000, CM = 900, XC = 90, IV = 4.

提示:

  • 1 <= s.length <= 15
  • s 仅含字符 (‘I’, ‘V’, ‘X’, ‘L’, ‘C’, ‘D’, ‘M’)
  • 题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
  • 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
  • IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
  • 关于罗马数字的详尽书写规则,可以参考 罗马数字 - Mathematics 。

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:暴力法

class Solution {
    Map<Character, Integer> symbolValues = new HashMap<Character, Integer>() {{
        put('I', 1);
        put('V', 5);
        put('X', 10);
        put('L', 50);
        put('C', 100);
        put('D', 500);
        put('M', 1000);
    }};

    public int romanToInt(String s) {
        int ans = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            int value = symbolValues.get(s.charAt(i));
            if (i < n - 1 && value < symbolValues.get(s.charAt(i + 1))) {
                ans -= value;
            } else {
                ans += value;
            }
        }
        return ans;
    }
}

通常情况下,罗马数字中小的数字在大的数字的右边。若输入的字符串满足该情况,那么可以将每个字符视作一个单独的值,累加每个字符对应的数值即可。

例如 XXVII\texttt{XXVII}XXVII 可视作 X+X+V+I+I=10+10+5+1+1=27\texttt{X}+\texttt{X}+\texttt{V}+\texttt{I}+\texttt{I}=10+10+5+1+1=27X+X+V+I+I=10+10+5+1+1=27。

若存在小的数字在大的数字的左边的情况,根据规则需要减去小的数字。对于这种情况,我们也可以将每个字符视作一个单独的值,若一个数字右侧的数字比它大,则将该数字的符号取反。

例如 XIV\texttt{XIV}XIV 可视作 X−I+V=10−1+5=14\texttt{X}-\texttt{I}+\texttt{V}=10-1+5=14X−I+V=10−1+5=14。

7.最后一个单词长度

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。

单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

示例

输入:s = “Hello World” 输出:5 解释:最后一个单词是“World”,长度为5。

输入:s = " fly me to the moon " 输出:4 解释:最后一个单词是“moon”,长度为4。

输入:s = “luffy is still joyboy” 输出:6 解释:最后一个单词是长度为6的“joyboy”。

提示:

1 <= s.length <= 104
s 仅有英文字母和空格 ’ ’ 组成
s 中至少存在一个单词

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:反向遍历

class Solution {
    public int lengthOfLastWord(String s) {
        int end = s.length() - 1;
        while (end >= 0 && s.charAt(end) == ' ') end--;
        if (end == -1) return 0;
        int start = end;
        while (start >= 0 && s.charAt(start) != ' ') start--;
        return end - start;
    }
}

8.最长公共前缀

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 " "。

示例

输入:strs = [“flower”,“flow”,“flight”] 输出:“fl”

输入:strs = [“dog”,“racecar”,“car”] 输出:“” 解释:输入不存在公共前缀。

提示:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i] 仅由小写英文字母组

带你刷算法——数组/字符串的完全掌握(一),解决算法,一个专栏就够了,全部文章,算法

题解

思路一:暴力法

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        int length = strs[0].length();
        int count = strs.length;
        for (int i = 0; i < length; i++) {
            char c = strs[0].charAt(i);
            for (int j = 1; j < count; j++) {
                if (i == strs[j].length() || strs[j].charAt(i) != c) {
                    return strs[0].substring(0, i);
                }
            }
        }
        return strs[0];
    }
}

上述代码使用了水平扫描法来找到最长公共前缀。以下是该算法的思路:

  1. 首先,检查输入的字符串数组是否为空或长度为0,如果是的话,直接返回空字符串。
  2. 初始化变量 length 为第一个字符串的长度,表示最长公共前缀的可能长度。
  3. 初始化变量 count 为字符串数组的长度,表示需要比较的字符串数量。
  4. 使用外层循环遍历第一个字符串的每个字符(索引从0到length-1)。
  5. 在每次循环中,用变量 c 存储当前字符。
  6. 使用内层循环遍历从第二个字符串到最后一个字符串(索引从1到count-1)。
  7. 在每次内层循环中,首先检查索引 i 是否超出了字符串的长度,或者当前字符串的字符与第一个字符串的字符不相等,如果是的话,说明当前字符不属于公共前缀,直接返回第一个字符串的子串从索引0到i-1的部分。
  8. 如果内层循环结束时没有返回,说明当前字符在所有字符串中都相等,继续下一个字符的比较。
  9. 如果外层循环结束时都没有返回,说明第一个字符串就是最长公共前缀,直接返回第一个字符串。

这种方法通过逐个字符的比较来寻找最长公共前缀,当遇到不相等的字符或字符串长度超出时即可得到结果。

小结

1.判断数组中相同的数,并判断了几次

以下是一个使用Java的示例代码来判断数组中相同的数,并计算它们出现的次数:

import java.util.HashMap;
import java.util.Map;

public class CountDuplicateNumbers {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5, 1, 3, 2, 4, 1};

        Map<Integer, Integer> countMap = new HashMap<>();
        for (int num : numbers) {
            if (countMap.containsKey(num)) {
                countMap.put(num, countMap.get(num) + 1);
            } else {
                countMap.put(num, 1);
            }
        }

        System.out.println("Duplicate numbers and their counts:");
        for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
            if (entry.getValue() > 1) {
                System.out.println(entry.getKey() + " - " + entry.getValue() + " times");
            }
        }
    }
}

这段代码使用了HashMap来存储每个数字及其出现的次数。首先,我们遍历数组中的每个元素,如果countMap中已经包含该数字,则将其对应的值加1;否则,在countMap中添加该数字并设置初始值为1。最后,我们遍历countMap并打印出现次数大于1的数字及其出现次数。

在上述示例中,输入的数组为{1, 2, 3, 4, 5, 1, 3, 2, 4, 1},输出结果为:

Duplicate numbers and their counts:
1 - 3 times
2 - 2 times
3 - 2 times
4 - 2 times

2.判断数组中两个数的最大差值

以下是使用Java编写的示例代码,用于找到数组中两个数的最大差值:

public class MaxDifference {
    public static void main(String[] args) {
        int[] numbers = {2, 5, 9, 3, 1, 12, 6, 8};

        int maxDifference = findMaxDifference(numbers);
        System.out.println("Maximum difference: " + maxDifference);
    }

    public static int findMaxDifference(int[] numbers) {
        if (numbers == null || numbers.length < 2) {
            throw new IllegalArgumentException("Array must contain at least 2 numbers");
        }

        int minNumber = numbers[0];
        int maxDifference = numbers[1] - minNumber;

        for (int i = 2; i < numbers.length; i++) {
            if (numbers[i - 1] < minNumber) {
                minNumber = numbers[i - 1];
            }

            int currentDifference = numbers[i] - minNumber;
            if (currentDifference > maxDifference) {
                maxDifference = currentDifference;
            }
        }

        return maxDifference;
    }
}

在上述示例中,我们定义了一个findMaxDifference方法,该方法接受一个整数数组作为输入,并返回数组中两个数的最大差值。首先,我们检查数组是否为空或长度小于2,如果是,则抛出IllegalArgumentException异常。

然后,我们初始化minNumber为数组的第一个元素,将maxDifference初始化为第二个元素减去minNumber。接下来,我们遍历数组从索引2开始的每个元素。如果当前元素之前的最小数字minNumber大于当前元素的前一个元素,则更新minNumber为前一个元素的值。

然后,我们计算当前元素与minNumber之间的差值,并将其存储在currentDifference变量中。如果currentDifference大于maxDifference,则更新maxDifferencecurrentDifference

最后,我们返回maxDifference作为结果。

在上述示例中,输入的数组为{2, 5, 9, 3, 1, 12, 6, 8},输出结果为:

Maximum difference: 11

这表示数组中的最大差值为11,即12减去1。

3.判断后一个数比前一个数的最大差值

以下是使用Java编写的示例代码,用于找到数组中后一个数比前一个数的最大差值:

public class MaxDifference {
    public static void main(String[] args) {
        int[] numbers = {2, 5, 9, 3, 1, 12, 6, 8};

        int maxDifference = findMaxDifference(numbers);
        System.out.println("Maximum difference between consecutive numbers: " + maxDifference);
    }

    public static int findMaxDifference(int[] numbers) {
        if (numbers == null || numbers.length < 2) {
            throw new IllegalArgumentException("Array must contain at least 2 numbers");
        }

        int maxDifference = Integer.MIN_VALUE;

        for (int i = 1; i < numbers.length; i++) {
            int currentDifference = numbers[i] - numbers[i - 1];
            if (currentDifference > maxDifference) {
                maxDifference = currentDifference;
            }
        }

        return maxDifference;
    }
}

在上述示例中,我们定义了一个findMaxDifference方法,该方法接受一个整数数组作为输入,并返回数组中后一个数比前一个数的最大差值。首先,我们检查数组是否为空或长度小于2,如果是,则抛出IllegalArgumentException异常。

然后,我们初始化maxDifferenceInteger.MIN_VALUE,这是一个较小的初始值,确保可以正确比较和更新最大差值。

接下来,我们遍历数组从索引1开始的每个元素。通过计算当前元素与其前一个元素的差值,并将其存储在currentDifference变量中。如果currentDifference大于maxDifference,则更新maxDifferencecurrentDifference

最后,我们返回maxDifference作为结果。

在上述示例中,输入的数组为{2, 5, 9, 3, 1, 12, 6, 8},输出结果为:

Maximum difference between consecutive numbers: 11

这表示数组中后一个数比前一个数的最大差值为11,即12减去1。

4.循环遍历字符串

以下是使用Java编写的示例代码,用于循环遍历字符串并打印每个字符:

public class LoopString {
    public static void main(String[] args) {
        String str = "Hello, World!";

        // 使用for循环遍历字符串
        System.out.println("Using for loop:");
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            System.out.println(ch);
        }

        // 使用增强型for循环遍历字符串
        System.out.println("Using enhanced for loop:");
        for (char ch : str.toCharArray()) {
            System.out.println(ch);
        }

        // 使用while循环遍历字符串
        System.out.println("Using while loop:");
        int index = 0;
        while (index < str.length()) {
            char ch = str.charAt(index);
            System.out.println(ch);
            index++;
        }
    }
}

在上述示例中,我们使用三种不同的循环方式来遍历字符串"Hello, World!"

首先,我们使用for循环来遍历字符串。通过获取字符串的长度str.length(),我们可以使用索引从0到字符串长度减1的范围来依次访问每个字符。使用charAt()方法,我们可以获取指定索引位置的字符,并将其打印出来。

然后,我们使用增强型for循环(也称为foreach循环)来遍历字符串。通过调用toCharArray()方法,我们可以将字符串转换为一个字符数组。这样,我们就可以直接遍历字符数组的每个元素,并将其打印出来。

最后,我们使用while循环来遍历字符串。通过定义一个索引变量index,并在每次迭代后递增它,我们可以依次访问字符串中的每个字符。在循环体中,我们使用charAt()方法获取指定索引位置的字符,并将其打印出来。

以上三种循环方式都会输出相同的结果,即遍历字符串并打印每个字符。

在上述示例中,输出结果为:

Using for loop:
H
e
l
l
o
,
 
W
o
r
l
d
!
Using enhanced for loop:
H
e
l
l
o
,
 
W
o
r
l
d
!
Using while loop:
H
e
l
l
o
,
 
W
o
r
l
d
!

5.判断字符串中的空格符号,并将第一个空格后面设置为第二个字符串,第二个空格为第三个字符串

以下是使用Java编写的示例代码,用于判断字符串中的空格符号,并将第一个空格后面的内容设置为第二个字符串,第二个空格后面的内容设置为第三个字符串:

public class SplitString {
    public static void main(String[] args) {
        String str = "Hello, World! This is a test.";

        // 使用split()方法分割字符串
        String[] parts = str.split("\\s+", 3);

        if (parts.length >= 3) {
            String firstString = parts[0];
            String secondString = parts[1];
            String thirdString = parts[2];

            System.out.println("First string: " + firstString);
            System.out.println("Second string: " + secondString);
            System.out.println("Third string: " + thirdString);
        } else {
            System.out.println("The input string does not contain enough spaces.");
        }
    }
}

在上述示例中,我们首先定义了一个输入字符串"Hello, World! This is a test."

然后,我们使用split()方法对输入字符串进行分割。split()方法以指定的正则表达式作为分隔符来拆分字符串。在这里,我们使用正则表达式\\s+,表示一个或多个连续的空白字符(包括空格、制表符、换行符等)作为分隔符。第二个参数3表示最大分割成三部分。

接下来,我们检查分割后的结果数组parts的长度是否大于等于3。如果是,则表示输入字符串中至少有两个空格符号。

然后,我们提取数组parts中的第一个、第二个和第三个元素作为相应的字符串变量:firstStringsecondStringthirdString

最后,我们打印输出每个字符串的内容。

在上述示例中,输出结果为:

First string: Hello,
Second string: World!
Third string: This is a test.

这表示输入字符串中的第一个空格后面的内容被设置为第二个字符串(“World!”),第二个空格后面的内容被设置为第三个字符串(“This is a test.”)。文章来源地址https://www.toymoban.com/news/detail-648957.html

到了这里,关于带你刷算法——数组/字符串的完全掌握(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法通关村十三关 | 数组字符串加法专题

    题目:LeetCode66,66. 加一 - 力扣(LeetCode) 我们只需要从头到尾依次运算,用常量标记是否进位,需要考虑的特殊情况是digits = [9,9,9]的时候进位,我们组要创建长度加1的数组,首位添加为1即可。         给定两个非负形式的字符串num1和num2,计算他们的和以字符串形式返

    2024年02月11日
    浏览(42)
  • 【每日挠头算法题(3)】字符串解码|数组中重复的数字

    点我直达~ 这道题怎么看都好像是用栈来实现,因为有左右括号。(可是第一时间我没想到) 遍历字符串,此时会有几种情况: 1.如果是数字字符,给一个 num 变量,将该字符转化成数字存储起来。 2.如果是字母(题目说只可能是小写),给一个字符串 str ,将该字母存储到字符

    2024年02月08日
    浏览(57)
  • 【数据结构】字符串匹配|BF算法|KMP算法|next数组的优化

    字符串匹配算法是在实际工程中经常遇到的问题,也是各大公司笔试面试的常考题目,本文主要介绍BF算法(最好想到的算法,也最好实现)和KMP算法(最经典的) BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标S的第一个字符与模式串T的第一

    2024年02月04日
    浏览(56)
  • 【编码狂想】LeetCode 字符串和数组篇:挑战算法精髓,深化程序设计基础

    ​ 🌈 个人主页: Sarapines Programmer  🔥 系列专栏: 本期文章收录在《C语言闯关笔记》,大家有兴趣可以浏览和关注,后面将会有更多精彩内容!  ⏰翰墨致赠:翩翩风华激彩虹,豪情壮志醉长空。 剑指星河舞红尘,梦驰烈马向未来。 ​ ​ 🎉欢迎大家关注🔍点赞👍收藏

    2024年02月04日
    浏览(52)
  • mysql 解析json字符串、数组字符串、json数组字符串

    笔者使用mysql 5.7进行了一次json字符串的解析,因为一直在搞大数据相关的数据库、olap等,太久没有用mysql5.x的版本,一些函数已经不知道支不支持,我的同事建议我使用like、rlike模糊匹配的方式,身为数据人我不太喜欢用这种手段,因为他们比较低效。于是我想这里总结一下

    2024年02月16日
    浏览(56)
  • JS中字符串切割为数组/数组拼接为字符串

    (1)语法格式: 其中所选分隔符使用双引号(“”)或者单引号(‘’)括起来; 所生成的数组会存放于前面定义的数组变量中。 (2)样例: JS代码: 运行结果: (3)其他用法: ①当所选分隔符为空时,返回的数组即将每个字符分割出来: JS代码: 运行结果: ②分隔

    2024年02月12日
    浏览(58)
  • 掌握字符与字符串:C语言中的神奇函数解析(一)

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 我们在学习C语言的过程中,除了使用最多的头文件stdio.h,还会使用其他头文件,利用其中的库函数帮助我们简化代码的过程,比如像math.h,string.h等头文

    2024年03月09日
    浏览(65)
  • 掌握字符与字符串:C语言中的神奇函数解析(二)

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 声明:int strncmp(const char *str1, const char *str2, size_t n) str1 -- 要进行比较的第一个字符串。 str2 -- 要进行比较的第二个字符串。 n -- 要比较的最大字符数。 作

    2024年03月09日
    浏览(67)
  • 掌握字符与字符串:C语言中的神奇函数解析(三)

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 除了字符函数和字符串函数,string.h中还有一类 内存操作函数 ,如memset(),memcmp()等函数,他们在功能和某些字符串函数很像,但作用范围更广,除了作用

    2024年03月09日
    浏览(44)
  • vue使用split()将字符串分割数组join()将数组转字符串reverse()将数组反转

    1.split() 将字符串切割成数组 输出如下 1.split()不传参数默认整个字符串作为数组的一个元素,返回包含原始字符串的数组 2.split(‘’)单引号不传参数默认将字符串拆分成一个个字符数组 如输入参数: const str = 123456789’ 拆分后:[‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’

    2023年04月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包