Press "Enter" to skip to content

分类: Leetcode

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

方法一、暴力方法

使用Python3内置index()find()函数进行逻辑判断

str.index(), str.find()函数两者区别:

str.find(sub[, start[, end]])
返回子字符串 sub 在 s[start:end] 切片内被找到的最小索引。 可选参数 start 与 end 会被解读为切片表示法。 如果 sub 未被找到则返回 -1。

str.index(sub[, start[, end]])
类似于 find(),但在找不到子字符串时会引发 ValueError

Python3 代码题解

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        if not haystack and not needle:
            return 0
        if needle in haystack:
            return haystack.index(needle)
        else:
            return -1

Source: LeetCode(The title reproduced in this blog is for personal study use only)

27. 移除元素

方法一、双指针

题目要求删除数组中等于val的所以元素,输出数组的长度小于或等于输入数组的长度,因此我们就可以把输出数组写在输入数组上。我们可以选择双指针:右指针i指向当前处理的数组元素,左指针cover_pointer指向下一个将要赋值的位置。

如果右指针指向的当前元素不等于valnums[i]输出一个元素,我们就将当前元素不等于val值,则复制到覆盖指针指向的位置,并向后移动一位。

如果右指针指向的当前元素等于val,不能输出到数组中左指针不动,并将右指针向后移动一位。

Python3 代码题解

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 初始化覆盖指针和数组长度
        cover_pointer = 0
        length = len(nums)
        for i in range(length):
            if nums[i] != val:
                # 如果当前元素不等于初始值,则复制到覆盖指针指向的位置
                nums[cover_pointer] = nums[i]
                # 覆盖指针向后移动一位
                cover_pointer += 1
        return cover_pointer

Source: LeetCode(The title reproduced in this blog is for personal study use only)

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

方法一、双指针

判断nums的长度是否为0,为0则不包含任何元素,因此返回0。当数组nums的长度大于0时,数组中此时至少包含一个元素,在删除重复元素之后也至少剩下一个元素,因此nums[0]保持原状即可,从下标1开始删除重复元素。

定义两个指针fastslow分别为快指针和慢指针,快指针则遍历数组到达下标的位置,慢指针表示下一个不同元素要填入的下标位置,初始时两个指针都指向下标sums[1]

Python3 代码题解

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if not nums:
            return 0

        n = len(nums)
        fast = slow = 1
        while fast < n:
            if nums[fast] != nums[fast - 1]:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1

        return slow

Source: LeetCode(The title reproduced in this blog is for personal study use only)

21. 合并两个有序链表

方法一、递归

List1或List2一开始就是空链表,那么不需要任何操作直接返回非空链表。否则我们就要判断List1或List2哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。

Python3 代码题解

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        if list1 is None:
            return list2
        elif list2 is None:
            return list1
        elif list1.val < list2.val:
            list1.next = self.mergeTwoLists(list1.next, list2)
            return list1
        else:
            list2.next = self.mergeTwoLists(list1, list2.next)
            return list2

Source: LeetCode(The title reproduced in this blog is for personal study use only)

20.有效的括号

方法一、栈

一、利用栈先入后出的特点,如果遇到左括号入栈,遇到右口号时将对应栈顶左括号出栈,则遍历完所以的括号后stack仍为空。
二、建立哈希表pairs构建左右括号的对应关系。

Python3 代码解释

class Solution:
    def isValid(self, s: str) -> bool:
        if len(s) % 2 == 1:
            return False

        pairs = {
            "}": "{",
            "]": "[",
            ")": "(",
        }
        stack = list()
        for i in s:
            if i in pairs:
                if not stack or stack[-1] != pairs[i]:
                    return False
                stack.pop()
            else:
                stack.append(i)

        return not stack

Source: LeetCode(The title reproduced in this blog is for personal study use only)

14. 最长公共前缀

方法一:

横向扫描
用LCP(S1…Sn)表示字符串S1…Sn的最长公共前缀。

LCP(S_1......S_n) = LCP(LCP(LCP(S_1,S_2),S_3),...S_n)

依次遍历字符串数组中的每个字符串,如果尚未遍历完所以的字符串时,最长公共前缀已经是空字符串,则最长公共前缀一定是空字符串。直接返回空字符串。

Python3 代码解法

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs:
            return ""

        prefix, cont = strs[0], len(strs)
        for i in range(1, cont):
            prefix = self.lcp(prefix, strs[i])
            if not prefix:
                break

        return prefix

    def lcp(self, str1, str2):
        length, index = min(len(str1), len(str2)), 0
        while index < length and str1[index] == str2[index]:
            index += 1
        return str1[:index]

Source: LeetCode(The title reproduced in this blog is for personal study use only)

13. 罗马数字转整数

方法一:

  • 创建一个哈希表将罗马字符与对应的数值关联起来。
  • 然后对字符串进行遍历,由于组合只有两种情况,一种是一个字符,一种是两个字符,其中两个字符优先于一个字符
  • 先判断两个字符的组合在哈希表中是否存在,存在则将值取出加到结果ans中,并向后移两个字符。不存在则判断当前1个字符是否存在,存在则将值去除加到结果ans中,并向后移1个字符,最后遍历结束返回结果ans

C 代码题解

int romanToInt(char* s) {
    int symbolValues[26];
    symbolValues['I' - 'A'] = 1;
    symbolValues['V' - 'A'] = 5;
    symbolValues['X' - 'A'] = 10;
    symbolValues['L' - 'A'] = 50;
    symbolValues['C' - 'A'] = 100;
    symbolValues['D' - 'A'] = 500;
    symbolValues['M' - 'A'] = 1000;
    int ans = 0;
    int n = strlen(s);
    for (int i = 0; i < n; ++i) {
        int value = symbolValues[s[i] - 'A'];
        if (i < n - 1 && value < symbolValues[s[i + 1] - 'A']) {
            ans -= value;
        } else {
            ans += value;
        }
    }
    return ans;
}

Python3 代码题解

class Solution:

    SYMBOL_VALUES =  {
        'I': 1,
        'V': 5,
        'X': 10,
        'L': 50,
        'C': 100,
        'D': 500,
        'M': 1000,
    }

    def romanToInt(self, s: str) -> int:
        ans = 0
        n = len(s)
        for i, ch in enumerate(s):
            value = Solution.SYMBOL_VALUES[ch]
            //判断当前字符是否是特殊情况,即当前字符的数值小于下一个字符的数值。如果是特殊情况,需要减去当前字符的数值。
            if i < n - 1 and value < Solution.SYMBOL_VALUES[s[i + 1]]:
                ans -= value
            else:
                ans += value 
        return ans

Source: LeetCode(The title reproduced in this blog is for personal study use only)

9. 回文数

方法一:

反转一半数字:例如输入1331,我们可以将数字“1331”的后半部分从“31”反转成“13”在和前半部分进行比较,如果二者相同我们就得知数字“1331”是回文数

C 代码解法

#include<stdbool.h>

bool isPalindrome(int x){
    // 特殊情况处理:如果 x 是负数或者末尾是 0 的非零数,则不可能是回文数
    if (x < 0 || (x != 0 && x % 10 == 0)){
        return false;
    }

    long reversed_num = 0;
    int original_x = x;

    //反转 x 的一半
    while (x > 0){
        int digit = x % 10;
        reversed_num = reversed_num * 10 + digit;
        x /= 10;
    }

    // 如果原始数字长度是奇数,去掉最后一位
    if (original_x == reversed_num || original_x == reversed_num / 10){
        return true;
    } else {
        return false;
    }
}

Python3 代码解法

class Solution:
    def isPalindrome(self, x: int) -> bool:
        x = str(x)
        if x == x[::-1]:
            return True
        else:
            return False

Source: LeetCode(The title reproduced in this blog is for personal study use only)

1. 两数之和

方法一:暴力枚举

最容易想到的方法是枚举数组中的每一个数x,寻找数组中是否存在 target - x

当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x

C 代码解法

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    for (int i = 0; i < numsSize; ++i){
        for(int j = i + 1; j < numsSize; ++j){
            if (nums[i] + nums[j] == target){
                int* ret = malloc(sizeof(int) * 2);
                ret[0] = i;
                ret[1] = j;
                *returnSize = 2;
                return ret;
            }
        }
    }
    *returnSize = 0;
    return NULL;
}

C++ 代码解法

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (nums[i] + nums[j] == target) {
                    return {i, j};
                }
            }
        }
        return {};
    }
};

Python3 代码解法

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] + nums[j] == target:
                    return [i,j]
        return []

Java 代码解法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int n = nums.length;
        for(int i = 0; i < n; ++i){
            for(int j = i + 1; j < n; ++j){
                if(nums[0] + nums[1] == target){
                    return new int[]{i,j};
                }
            }
        }
        return new int[0];
    }
}

复杂度分析 时间复杂度:O(N^2),其中 N 是数组中的元素数量。最坏情况下数组中任意两个数都要被匹配一次。 空间复杂度:O(1)。

方法二:哈希表

注意到方法一的时间复杂度较高的原因是寻找到 target - x 的时间复杂度过高。因此,我们需要一个更优秀的方法,能够快速寻找数组中是否存在目标元素。如果存在,我们需要找出他的索引。

使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N) 降低到 O(1) 。

这样我们创建一个哈希表,对于每一个 x ,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。

Python 代码解法

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable = dict()
        for i, num in enumerate(nums):
            if target - num in hashtable:
                return [hashtable[target - num], i]
            hashtable[nums[i]] = i
        return []

Java 代码解法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; ++i) {
            if (hashtable.containsKey(target - nums[i])) {
                return new int[]{hashtable.get(target - nums[i]), i};
            }
            hashtable.put(nums[i], i);
        }
        return new int[0];
    }   
}

Source: LeetCode(The title reproduced in this blog is for personal study use only)