快排、反转链表、最长有效括号、寻找重复数
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 边界条件