LeetCode之数组/字符串

88. 合并两个有序数组

class Solution {

    public void merge(int[] nums1, int m, int[] nums2, int n) {
        // 这个循环将 nums2 中的元素逐个复制到 nums1 中从索引 m 开始的位置
        for(int i = 0; i < n; i++) {
            nums1[i + m] = nums2[i];
        }
        // 使用 Java 内置的 Arrays.sort 方法对合并后的 nums1 数组进行排序
        Arrays.sort(nums1);
    }
    
}

27. 移除元素

class Solution {

    public int removeElement(int[] nums, int val) {
        // 定义一个指针 l ,初始值为 0 ,用于标记新数组的位置
        int l = 0;
        // 遍历 nums 数组中的每个元素
        for (int num : nums) {
            // 如果当前元素等于指定的值 val ,则跳过本次循环
            if (num == val) {
                continue;
            }
            // 将不等于 val 的元素放到新位置(由 l 指示)
            nums[l] = num;
            // 移动指针 l ,指向下一个位置
            l = l + 1;
        }
        // 返回新数组的长度(即不等于 val 的元素个数)
        return l;
    }
}

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

class Solution {
    public int removeDuplicates(int[] nums) {
        // 如果数组长度为 0,直接返回 0
        if (nums.length == 0) {
            return 0;
        }
        // 初始化慢指针 i 为 1,指向数组第二个元素
        int i = 1;
        // 使用快指针 j 遍历数组,从第二个元素开始(索引为 1)
        for (int j = 1; j < nums.length; j++) {
            // 如果快指针指向的元素和慢指针前一个位置的元素不相等
            if (nums[i - 1] != nums[j]) {
                // 将快指针指向的元素赋值给慢指针位置的元素
                nums[i] = nums[j];
                // 慢指针向后移动一位
                i = i + 1;
            }
        }
        // 返回慢指针的位置,即去除重复元素后数组的长度
        return i;
    }

}

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

class Solution {

    public int removeDuplicates(int[] nums) {
        // 如果数组长度小于等于2,则直接返回数组长度
        if (nums.length <= 2) {
            return nums.length;
        }
        // 初始化两个指针,slow用于记录新数组的长度和待插入元素的位置,fast用于遍历原数组
        int slow = 2;
        int fast = 2;
        // 开始遍历数组
        while (fast < nums.length) {
            // 当发现当前元素和前面两个待保持的元素不同时,说明当前元素可以保留
            if (nums[slow - 2] != nums[fast]) {
                // 将当前fast指向的元素放到slow指向的位置
                nums[slow] = nums[fast];
                // 更新slow指针,指向下一个待插入的位置
                ++slow;
            }
            // 更新fast指针,继续往后遍历
            ++fast;
        }
        // 返回新数组的长度
        return slow;
    }

}

169. 多数元素

class Solution {

    public int majorityElement(int[] nums) {
        // 对给定的整数数组 nums 进行排序
        Arrays.sort(nums);
        // 返回排序后数组中间位置的元素
        return nums[nums.length / 2];
    }

}

189. 轮转数组

class Solution {

    // 定义一个公共静态方法 rotate,接收一个整数数组 nums 和旋转步数 k
    public void rotate(int[] nums, int k) {
        // // 创建一个与 nums 长度相同的新数组 newArr    
        int[] newArr = new int[nums.length];

        // // 遍历原数组 nums
        for (int i = 0; i < nums.length; i++) {
            // 根据当前索引 i 和旋转步数 k 计算新数组中应放置的索引
            // 使用 % 运算符确保索引在数组范围内
            newArr[(i + k) % nums.length] = nums[i];
        }

        // 将新数组 newArr 的内容复制到原数组 nums 中
        System.arraycopy(newArr, 0, nums, 0, nums.length);
    }

}

121. 买卖股票的最佳时机

class Solution {
    public int maxProfit(int[] prices) {

        // [7,1,5,3,6,4]
        int minPrice = prices[0];
        int ans = 0;
        for (int i = 0; i < prices.length; i++) {
            minPrice = Math.min(minPrice, prices[i]);
            ans = Math.max(ans, prices[i] - minPrice);
        }
        return ans;

    }
}

122. 买卖股票的最佳时机 II

class Solution {

    // 定义一个公共方法 maxProfit,接收一个整数数组 prices,表示股票价格
    public int maxProfit(int[] prices) {

        // 初始化 result 为 0,用于累计最大利润
        int result = 0;

        // 从第二天开始遍历价格数组
        for (int i = 1; i < prices.length; i++) {

            // 如果当前价格高于前一天的价格
            if (prices[i - 1] < prices[i]) {

                // 累计利润:当前价格减去前一天的价格
                result += (prices[i] - prices[i - 1]);
            }
        }

        // 返回累计的最大利润
        return result;
    }

}

55. 跳跃游戏

class Solution {

    // 定义一个公共方法 canJump,接收一个整数数组 nums,表示每个位置的最大跳跃长度
    public boolean canJump(int[] nums) {

        // 初始化一个变量 rightmost,用于记录能跳到的最远位置
        int rightMost = 0;

        // 遍历数组
        for (int i = 0; i < nums.length; i++) {
            // 如果当前索引 i 在能跳跃的范围内
            if (i <= rightMost) {
                // 更新 rightmost 为当前位置可以跳跃到的最远位置
             rightMost = Math.max(rightMost, i + nums[i]);
             // 如果能跳到或超过最后一个位置,返回 true
             if (rightMost >= nums.length - 1) {
                return true;
             } 
            }
       
        }
        // 如果遍历结束仍未能跳到最后一个位置,返回 false
        return false;

    }

}

45. 跳跃游戏 II

class Solution {

    // 定义一个公共方法 jump,接收一个整数数组 nums,表示每个位置的最大跳跃长度
    public int jump(int[] nums) {
        // maxPosition 初始化,用于记录当前能跳到的最远位置
        int maxPosition = 0;
        // 初始化 end,表示当前的跳跃终点
        int end = 0;
        // 初始化 steps,表示跳跃的次数
        int steps = 0;
        // 遍历数组,直到倒数第二个元素(因为最后一个不需要跳跃)
        for (int i = 0; i < nums.length - 1; i++) {
            // 更新最远位置,可以跳到的最大索引
            maxPosition = Math.max(maxPosition, i + nums[i]);
            // 如果到达当前跳跃的终点
            if (i == end) {
                // 更新跳跃终点为 maxPosition
                end = maxPosition;
                // 增加跳跃次数
                steps++;
            }
        }
        // 返回总的跳跃次数
        return steps;
    }

}

274. H 指数

class Solution {

    // 定义一个公共方法 hIndex,接收一个整数数组 citations,表示引文次数
    public int hIndex(int[] citations) {
        // 对引文次数数组进行排序
        Arrays.sort(citations);

        // 初始化索引 i 为数组的最后一个元素
        int i = citations.length - 1;

        // 初始化 h 为 0,用于记录 h 指数
        int h = 0;

        // 遍历数组,直到索引 i 小于 0 或当前引文次数 citations[i] 小于等于 h
        while (i >= 0 && citations[i] > h) {
            // 每次循环,增加 h 的值
            h++;
            // 移动到前一个引文次数
            i--;
        }
        // 返回最终计算的 h 指数
        return h;
    }
}

380. O(1) 时间插入、删除和获取随机元素

class RandomizedSet {
    // 用于存储元素的列表
    List<Integer> nums;
    // 用于存储元素及其在 nums 列表中索引的映射
    Map<Integer, Integer> indices;
    // 随机数生成器
    Random random;


    public RandomizedSet() {
        // 初始化 nums 列表
        nums = new ArrayList<>();
        // 初始化索引映射
        indices = new HashMap<>();
        // 初始化随机数生成器
        random = new Random();
    }
    
    // 插入一个新的元素 val
    public boolean insert(int val) {
        // 如果 val 已存在于 indices 中,返回 false
        if (indices.containsKey(val)) {
            return false;
        }
        // 记录 val 对应的索引
        indices.put(val, nums.size());
        // 将 val 添加到 nums 列表的末尾
        nums.add(val);
        return true;
    }
    
    // 移除元素 val
    public boolean remove(int val) {
        // 如果 val 不存在,返回 false
        if (!indices.containsKey(val)) {
            return false;
        }
        // 获取 val 的索引
        int index = indices.get(val);
        // 获取 nums 列表最后一个元素
        int last = nums.get(nums.size() - 1);
        // 将最后一个元素放到 val 的位置上
        nums.set(index, last);
        // 更新 last 元素在 indices 中的索引
        indices.put(last, index);
        // 从 nums 列表中移除最后一个元素
        nums.remove(nums.size() - 1);
        // 从 indices 中移除 val
        indices.remove(val);
        // 返回 true,表示移除成功
        return true;
    }
    
    // 返回一个随机元素
    public int getRandom() {
        // 生成一个随机索引
        int randomIndex = random.nextInt(nums.size());
        // 返回随机索引对应的元素
        return nums.get(randomIndex);
    }
}

/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet obj = new RandomizedSet();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */

238. 除自身以外数组的乘积

class Solution {

    /**
     * 题目:除自身以外数组的乘积
     * 思路:计算当前元素,所有左右前缀数组乘积,然后再遍历原数组,当前位置的左右前缀乘积再相乘
     *
     * 输入:nums = {1,2,3,4}
     * 输出:answer = {24,12,8,6}
     * @param nums 输入数组
     * @return 除自身以外数组的乘积
     */
    public static int[] productExceptSelf(int[] nums) {
        // 初始化左前缀乘积数组
        int[] leftSum = new int[nums.length];
        // 初始化右前缀乘积数组
        int[] rightSum = new int[nums.length];

        // 边界定义,索引0左前缀无元素,初始化为1
        leftSum[0] = 1;
        // 排除边界开始计算,当前元素后一个元素 * 后一个元素左前缀乘积,即是当前元素的左前缀乘积
        for (int i = 1; i < nums.length; i++) {
            leftSum[i] = nums[i - 1] * leftSum[i - 1];
        }

        // 边界定义,索引nums.length -1右前缀无元素,右前缀乘积初始化为1
        rightSum[nums.length - 1] = 1;

        // 排除边界开始计算,当前元素前一个元素 * 前一个元素右前缀乘积,即是当前元素的右前缀乘积
        for (int i = nums.length - 2; i >= 0; i--) {
            rightSum[i] = nums[i + 1] * rightSum[i + 1];
        }


        int[] result = new int[nums.length];
        // 当前元素的所有乘积,即是当前元素的所有左前缀与右前缀乘积
        for (int i = 0; i< nums.length; i++) {
            result[i] = leftSum[i] * rightSum[i];
        }
        System.out.println(Arrays.toString(result));
        return result;
    }

}


134. 加油站

class Solution {

    // 方法 canCompleteCircuit 接收两个列表 gas 和 cost,返回可以完成一圈的起始站点索引
    public int canCompleteCircuit(int[] gas, int[] cost) {
        // 用于累计当前的净油量
        int sum = 0;
        // 用于记录当前的最大净油量
        int sumMax = 0;
        // 用于记录可能的起始站点
        int ans = 0;

        // 从后往前遍历 gas 和 cost 列表
        for (int i = gas.length - 1; i >= 0; i--) {
            // 计算当前站点的净油量
            sum += gas[i] - cost[i];
            // 更新当前的最大净油量
            sumMax = Math.max(sum, sumMax);
            // 如果当前的净油量大于等于最大净油量,记录当前站点为可能的起始点
            if (sum >= sumMax) {
                ans = i;
            }
        }
        // 如果总的净油量大于等于 0,返回可能的起始点;否则返回 -1
        return sum >= 0 ? ans : -1;
    }

}

13. 罗马数字转整数

class Solution {

     // 方法:将罗马数字转换为整数
    public int romanToInt(String s) {
        // 初始化累加器,用于存储转换后的整数值
        int sum = 0;
        // 获取第一个字符的值
        int preNum = getValue(s.charAt(0));

        // 遍历字符串的每个字符,从第二个字符开始
        for (int i = 1; i < s.length(); i++) {
            // 获取当前字符的值
            int num = getValue(s.charAt(i));

            // 如果前一个字符的值小于当前字符的值,表示需要减去前一个值
            if (preNum < num) {
                // 从 sum 中减去前一个字符的值
                sum = sum - preNum;
            } else {
                // 否则,将前一个字符的值加到 sum 中
                sum = sum + preNum;
            }

            // 更新前一个字符的值为当前字符的值
            preNum = num;
        }
        // 将最后一个字符的值加到 sum 中
        sum = sum + preNum;
        // 返回转换后的整数值
        return sum;

    }

    // 辅助方法:将罗马数字字符转换为对应的整数值
    private int getValue(char ch) {    
        switch(ch) {
            case 'I':
                return 1;
            case 'V':
                return 5;
            case 'X':
                return 10;
            case 'L':
                return 50;
            case 'C':
                return 100;
            case 'D':
                return 500;
            case 'M':
                return 1000;
            default:
                return 0;
        } 
    }

}

12. 整数转罗马数字

class Solution {

    public String intToRoman(int num) {
        // 定义罗马数字和对应的整数值
        int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        
        String[] symbals = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        
        // 创建一个可变的字符串缓冲区用于存储生成的罗马数字
        StringBuilder sb = new StringBuilder();

        // 遍历整数值数组
        for (int i = 0; i < values.length; i++) {
            // 当输入的整数 num 大于等于当前整数值时
            while(values[i] <= num) {
                // 将对应的罗马数字符号添加到结果字符串缓冲区中
                sb.append(symbals[i]);
                // 从 num 中减去当前整数值
                num = num - values[i];
                
            }
            // 如果 num 变为 0,表示已经转换完成,退出循环
            if (num == 0) {
                break;
            }
        }
        // 将字符串缓冲区转换为字符串并返回
        return sb.toString();
    }
}

58. 最后一个单词的长度

class Solution {

    // 方法:计算字符串中最后一个单词的长度
    public int lengthOfLastWord(String s) {
        // "the moon  " 

        // 去除字符串两端的空白字符
        s = s.trim();

        // 通过总长度减去最后一个空格的索引来计算最后一个单词的长度
        // s.length() - 1 是为了得到最后一个字符的索引
        // s.lastIndexOf(" ") 返回最后一个空格的索引
        return s.length() - 1 - s.lastIndexOf(" ");
    }
}

14. 最长公共前缀

class Solution {

    // 方法:找到字符串数组中最长的公共前缀
    public String longestCommonPrefix(String[] strs) {
        // ["flower","flow","flight"]

        // 如果数组为空,返回空字符串
        if (strs.length == 0) {
            return "";
        }
        System.out.println(Arrays.toString(strs));

        // 对字符串数组进行排序,以便之后容易找到公共前缀,因为排序后相同前缀的字符串会相邻
        Arrays.sort(strs);

        // 获取排序后的第一个字符串
        String start = strs[0];
        // 获取排序后的最后一个字符串
        String end = strs[strs.length - 1];

        // 计算这两个字符串的最小长度,以防止访问超出范围
        int num = Math.min(start.length(), end.length());

        int result = 0;
        // 逐个字符比较第一个和最后一个字符串,直到不同字符或达到最小长度为止
        for (int i = 0; i < num && start.charAt(i) == end.charAt(i); i++) {
            result = result + 1;
        }

        // 使用 substring 方法返回从第一个字符串开始到位置 result 的子字符串,即最长的公共前缀
        return start.substring(0, result);
    }

}

151. 反转字符串中的单词

class Solution {
    public String reverseWords(String s) {
        // 除去开头和末尾的空白字符
        s = s.trim();
        // 正则匹配连续的空白字符作为分隔符分割
        List<String> list = Arrays.asList(s.split("\\s+"));
        System.out.println(list);
        // 列表反正
        Collections.reverse(list);
        // 使用join拼接
        return String.join(" ", list);
    }

}

6. Z 字形变换

class Solution {

    public String convert(String s, int numRows) {
        // 字符串长度
        int n = s.length();
        // 行数
        int r = numRows;
        // 如果行数为 1 或者行数大于等于字符串长度,直接返回原字符串
        if (r == 1 || numRows >= n) {
            return s;
        }
        // 计算周期长度
        int t = r * 2 - 2;
        // 计算二维数组的列数
        int c = (n + t - 1) / t * (r - 1);

        // 创建二维字符数组        
        char[][] mat = new char[r][c];

        // 遍历字符串中的每个字符
        for (int i = 0, x = 0, y = 0; i < n; i++) {
            // 将当前字符放入二维数组中
            mat[x][y] = s.charAt(i);
            // 如果当前位置在周期的前半部分,向下移动
            if (i % t < r - 1) {
                x++;
            } else {
                // 如果在周期的后半部分,向右上移动
                x--;
                y++;
            }
        }

        // 创建字符串缓冲区用于存储结果
        StringBuilder sb = new StringBuilder();
        // 遍历二维数组的每一行
        for (int i = 0; i < mat.length; i++) {
            // 遍历每一行中的每个字符
            for (int j = 0; j < mat[i].length; j++) {
                // 如果字符不为空,将其添加到结果字符串缓冲区中
                if (mat[i][j] != 0) {
                    sb.append(mat[i][j]);
                }
            }
        }
        // 将字符串缓冲区转换为字符串并返回
        return sb.toString();
    }

}

28. 找出字符串中第一个匹配项的下标

class Solution {

    // 方法:在主字符串 haystack 中查找子字符串 needle
    public int strStr(String haystack, String needle) {
        // 获取主字符串 haystack 的长度
        int n = haystack.length();
        // 获取子字符串 needle 的长度
        int m = needle.length();

        // 遍历 haystack,直到剩余字符不足以容纳 needle
        for (int i = 0; i <= n - m; i++) {
            // 初始化标志,表示当前字符匹配
            boolean flag = true;
            // 遍历 needle 的每个字符,检查是否与 haystack 的当前子串匹配
            for (int j = 0; j < m; j++) {
                // 如果当前字符不匹配
                if (haystack.charAt(i + j) != needle.charAt(j)) {
                    // 设置标志为 false,表示不匹配
                    flag = false;
                    // 跳出内层循环
                    break;
                }
            }
            // 如果所有字符匹配,即 flag 仍为 true
            if (flag) {
                // 返回当前起始索引 i
                return i;
            }
        }
        // 如果没有找到 needle,返回 -1
        return -1;

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值