力扣刷题8-快排、反转链表、最长有效括号、寻找重复数

71 阅读4分钟

快排、反转链表、最长有效括号、寻找重复数

215 数组中第k个最大元素

题目描述:给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。时间复杂度为 O(n) 的算法解决此问题。 输入:[3,2,1,5,6,4], k=2 输出:5

题解: 快速排序算法O(nlog(n))

// 哨兵划分
private int partition(int[] nums, int l, int r) {
    int i = l;
    int j = r;
    while (i < j) {
        while (i < j && nums[j] >= nums[l]) {
            j--;
        }
        while (i < j && nums[i] <= nums[l]) {
            i++;
        }
        swap(nums, i, j);
    }
    //swap i, left,基准交换到两个子数组分界
    swap(nums, i, l);
    return i; //返回分界线索引
}

void quickSort(int[] nums, int l, int r) {
    if (l >= r) {
        return;
    }
    int pivot = partition(nums, l, r);
    // 递归左右数组
    quickSort(nums, l, pivot - 1); 
    quickSort(nums, pivot + 1, r);
}

改进快速排序算法, 「快速选择」算法:在分解的过程当中,我们会对子数组进行划分,如果划分得到的 pivot 正好就是我们需要的下标,就直接返回 a[k];否则,如果 pivot 比目标下标k小,就递归右子区间,否则递归左子区间。这样就可以把原来递归两个区间变成只递归一个区间,提高了时间效率。

private int quickSelect(int[] nums, int l, int r, int k) {
    if (l == r) {
        return nums[k];
    }
    int pivot = partition(nums, l, r);
    if (k <= pivot) {
        return quickSelect(nums, l, pivot, k);
    } else {
        return quickSelect(nums, pivot+1, r, k);
    }
}

public int findKthLargest(int[] nums, int k) {
    int n = nums.length;
//  quickSort(nums, 0, n - 1);
//  return nums[n - k];
    // 取第k个最大元素,等价于排序后取第(n-k)个元素,下标从0开始
    return quickSelect(nums, 0, n-1, n-k);
}

206.反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表 题解:

prev = null;
cur = head;
while (cur != null) {
    next = cur.next;
    cur.next = prev;
    prev = cur;
    cur = next;
}
return prev;

32 最长有效括号

题目:给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。 输入:"(()" 输出:2

题解:使用栈。栈底元素是当前已遍历过元素中最后一个没被匹配的右括号下标,栈里其他元素是左括号下标。 算法如下:

  • 遇到左括号,入栈
  • 遇到右括号,执行出栈顶元素 如果栈为空,说明当前右括号为没被匹配的右括号,入栈 如果栈不空,当前右括号下标减去栈顶元素,即为以该右括号结尾的最长有效长度

特殊情况,初始化栈底应该有个没被匹配的右括号下标,注入值为-1的元素

// java stack
stk.pop()
stk.push()
stk.peek()
for (int i=0; i< n; i++) {
    if (s.charAt(i) == '(') {
        stk.push(i);
    } else {
        stk.pop();
        if (stk.isEmpty()) {
            stk.push(i);
        } else {
            int top = stk.peek();
            res = Math.max(res, (i - top));
        }
    }
}

791. 自定义字符串排序

题目描述:给定两个字符串 order 和 s 。order 的所有字母都是 唯一 的,并且以前按照一些自定义的顺序排序。 输入 order = "cba", s = "abcd" 输出 “cbad”

题解:把order字符串按照出现顺序,设置权值。 第一个出现的字符的权值赋值为 1,第二个出现的字符的权值赋值为 2,以此类推。在遍历完成之后,所有未出现字符的权值默认赋值为 0

根据权值表,对字符串 s 进行排序。

442 数组中重复数据

nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次。 O(n) 且仅使用常量额外空间

题解:使用正负号标记,算法如下: 遍历第i元素,判断 (1)nums[nums[i] - 1] 是正数,说明nums[i] 第1次出现,设置该索引位置为负数 即设置nums[nums[i] - 1] (2)nums[nums[i] - 1] 是负数,说明nums[i] 第2次出现,nums[i]加入res

 for (int i = 0; i < n; i++) {
    int val = Math.abs(nums[i]);
    if (nums[val - 1] > 0) {
        nums[val - 1] *= -1;
    } else {
        res.add(val);
    }
}

153 寻找旋转排序数组中的最小值

题目:若旋转 4 次,则可以得到 [4,5,6,7,0,1,2],请你找出并返回数组中的 最小元素 。 你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

题解:二分查找 如果 nums[pivot] < nums[high],则说明最低点在左区间; 否则 最低点在右区间。

 while (low < high) {
    int pivot = low + (high - low) / 2;
    if (nums[pivot] < nums[high]) {
        high = pivot;   // key point
    } else {
        low = pivot + 1;
    }
}

注意low、high 边界条件