1. 两数之和【简单】
https://leetcode-cn.com/problems/two-sum/
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashmap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (hashmap.containsKey(target - nums[i])) {
return new int[]{ hashmap.get(target - nums[i]), i };
}
else {
hashmap.put(nums[i], i);
}
}
return null;
}
}
215.数组中的第K个最大元素【中等】
https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
这道题主要就是考察排序算法,我们可以用快速排序、堆排序两种方法。这两种基础排序算法一定要掌握。
利用快速排序思想:
因为经过一轮快速排序中的partition,我们能够让某一个值放到他应该在的位置,如下面例子中的 “6” , 它通过将小于它的值都放到它前面,大于它的值放到它后面,来确定了自己的位置(虽然前后的值的顺序是乱序的,但是不重要)。所以我们可以通过partition后这个值的index,来确定是不是target(第K大的元素)。如果不是,根据他的index与target的大小比较,我们可以缩小操作范围,从而节省时间。如: 我们此时把数字6的位置确定了,他在 index = 4 的位置,而假如要找倒数第一大的话,我们就需要找 index = nums.length - 1(本例中为7)位置的数。4 < 7,因此我们从6的后面开始找即可,而不用考虑6前面的数了。
class Solution {
public int findKthLargest(int[] nums, int k) {
int len = nums.length;
int target = len - k;
int left = 0, right = len - 1;
while (true) {
int index = partition(nums, left, right);
if (index == target)
return nums[target];
else if (index < target)
left = index + 1;
else if (index > target)
right = index - 1;
}
}
private int partition (int[] nums, int left, int right) {
int pivot = nums[left]; // 定义轴值
int j = left;
for (int i = left + 1; i <= right; i++) { // 只需要从(left, right]之间找target就行了
if (nums[i] < pivot) {
j++;
swap (nums, j, i); // 将[left+1,right]的值分好,left是本次的轴值
}
}
swap(nums, j, left);// 把left插到对应位置
return j;
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}
利用小根堆思想:
15. 三数之和【中等】
https://leetcode-cn.com/problems/3sum/
排序 + 双指针,对 sum 及 left、right 指针指向的数分治。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if (nums == null || nums.length < 3)
return res;
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0)
break;
if (i > 0 && nums[i] == nums[i-1])
continue;
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
res.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (left < right && nums[left+1] == nums[left]) left++;
while (left < right && nums[right - 1] == nums[right]) right--;
left ++;
right --;
}
else if (sum < 0) left++;
else if (sum > 0) right--;
}
}
return res;
}
}
912. 排序数组(请至少尝试2种及以上的排序算法)【中等】
https://leetcode-cn.com/problems/sort-an-array/
推排序
class Solution {
public int[] sortArray(int[] nums) {
int len = nums.length;
int[] a = new int[len + 1];
for (int i = 0; i < nums.length; ++i) {
a[i+1] = nums[i];
}
//下沉建堆
for (int i = len/2; i >= 1; --i) {
sink(a,i,len);
}
int k = len;
//排序
while (k > 1) {
swap(a,1,k--);
sink(a,1,k);
}
for (int i = 1; i < len+1; ++i) {
nums[i-1] = a[i];
}
return nums;
}
public void sink (int[] nums, int k,int end) {
//下沉
while (2 * k <= end) {
int j = 2 * k;
//找出子节点中最大或最小的那个
if (j + 1 <= end && nums[j + 1] > nums[j]) {
j++;
}
if (nums[j] > nums[k]) {
swap(nums, j, k);
} else {
break;
}
k = j;
}
}
public void swap (int nums[], int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
快速排序
class Solution {
public int[] sortArray (int[] nums) {
quickSort(nums,0,nums.length-1);
return nums;
}
public void quickSort (int[] nums, int low, int high) {
if (low < high) {
int index = partition(nums,low,high);
quickSort(nums,low,index-1);
quickSort(nums,index+1,high);
}
}
public int partition (int[] nums, int low, int high) {
int pivot = nums[low];
int start = low;
while (low < high) {
while (low < high && nums[high] >= pivot) high--;
while (low < high && nums[low] <= pivot) low++;
if (low >= high) break;
swap(nums, low, high);
}
//基准值归位
swap(nums,start,low);
return low;
}
public void swap (int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}