数组
第2题 两数之和
public int[] twoSum(int[] nums, int target) {
//使用hash实现
//原理:根据key去查找,hashmap的value存储的是key对应的数组下标
Map<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; i++) {
if (hashMap.containsKey(target - nums[i])){
return new int[]{i,hashMap.get(target - nums[i])};
}
hashMap.put(nums[i],i);
}
return new int[0];
}
第4题 寻找两个正序数组的中位数
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n = nums1.length;
int m = nums2.length;
int left = (n + m + 1) / 2;
int right = (n + m + 2) / 2;
//将偶数和奇数的情况合并,如果是奇数,会求两次同样的 k 。
return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;
}
private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
//让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1
if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);
if (len1 == 0) return nums2[start2 + k - 1];
if (k == 1) return Math.min(nums1[start1], nums2[start2]);
int i = start1 + Math.min(len1, k / 2) - 1;
int j = start2 + Math.min(len2, k / 2) - 1;
if (nums1[i] > nums2[j]) {
return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
}
else {
return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
}
}
第11题 盛最多水的容器
public int maxArea(int[] height) {
int left = 0;
int right = height.length -1;
int maxArea = 0;
while (left < right){
int area = (right - left) * Math.min(height[left], height[right]);
if (maxArea < area){
maxArea = area;
}
if (height[left] < height[right]){
left++;
}else if (height[left] >= height[right]){
right--;
}
}
return maxArea;
}
第15题 三数之和
解题办法:排序+双指针
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> list = new ArrayList<Integer>();
list.add(nums[first]);
list.add(nums[second]);
list.add(nums[third]);
ans.add(list);
}
}
}
return ans;
}
第16题 最接近的三数之和
public static int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int result = Integer.MAX_VALUE;
int differenceValue = Integer.MAX_VALUE;
int left = 0;
int right = 0;
int sum = 0;
int abs = 0;
for (int i = 0; i < nums.length; i++) {
left = i + 1;
right = nums.length - 1;
while (left < right){
sum = nums[i] + nums[left] + nums[right];
abs = Math.abs(sum - target);
if(abs == 0){
return sum;
}
if(abs < differenceValue){
result = sum;
differenceValue = abs;
}
if(sum > target){
int x = right - 1;
// 移动到下一个不相等的元素
while (left < x && nums[x] == nums[right]) {
x--;
}
right = x;
}else {
int y = left + 1;
// 移动到下一个不相等的元素
while (y < right && nums[y] == nums[left]) {
y++;
}
left = y;
}
}
}
return result;
}
第18题 四数之和
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> quadruplets = new ArrayList<List<Integer>>();
if (nums == null || nums.length < 4) {
return quadruplets;
}
Arrays.sort(nums);
int length = nums.length;
for (int i = 0; i < length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for (int j = i + 1; j < length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
quadruplets.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return quadruplets;
}
}
第26题 删除有序数组中的重复项
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0) return 0;
int p = 0;
int q = 1;
while(q < nums.length){
if(nums[p] != nums[q]){
nums[p + 1] = nums[q];
p++;
}
q++;
}
return p + 1;
}
第27题 移除元素
public int removeElement(int[] nums, int val) {
if(nums == null || nums.length == 0 || (nums.length == 1 && nums[0] == val)) return 0;
if(nums.length == 1) return 1;
//双指针
int left = 0;
int right = nums.length - 1;
while (left < right ){
//左指针先指向和val相等的值
while (nums[left] != val && left < right){
left++;
}
//右指针从最右边开始指向不等于val的值
while (nums[right] == val && left < right){
right--;
}
if (left < right){
nums[left] = nums[right];
right--;
}
}
if (nums[left] == val){
return left;
}else if ((left - 1) >= 0 && nums[left - 1] == val){
return left - 1;
}
return left + 1;
}
第31题 下一个排列
class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = nums.length - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
swap(nums, i, j);
}
reverse(nums, i + 1);
}
public void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public void reverse(int[] nums, int start) {
int left = start, right = nums.length - 1;
while (left < right) {
swap(nums, left, right);
left++;
right--;
}
}
}
第33题 搜索旋转排序数组
class Solution {
public int search(int[] nums, int target) {
//二分的思路:从题目的描述可以知道,整个数组旋转后的后面k个数字一定小于前面的n-k个数字
//那么在二分的时候,除了要判断当前的target和nums[middle]的值大小,还需要额外判断当前中点middle
//和n-k的关系,在其左边还是在右边
int result = -1;
int n = nums.length;
if (n == 0) return -1;
if (n == 1){
return nums[0] == target ? 0 : -1;
}
int left = 0;
int right = n -1;
int mid = 0;
while (left <= right){
mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
if (nums[0] <= nums [mid]){
//左边是升序区间 右边是无序区间
if(nums[0] <= target && target < nums[mid]){
right = mid - 1;
}else {
left = mid + 1;
}
}else {
//右边是降序区间 左边是无序区间
if (nums[mid] < target && target <= nums[n-1]){
left = mid + 1;
}else {
right = mid - 1;
}
}
}
return result;
}
}
第34题 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftIdx = binarySearch(nums, target, true);
int rightIdx = binarySearch(nums, target, false);
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
return new int[]{leftIdx, rightIdx};
}
return new int[]{-1, -1};
}
public int binarySearch(int[] nums, int target, boolean lower){
int left = 0, right = nums.length - 1, ans = nums.length;
while (left <= right){
int mid = (right + left) / 2;
if (lower){
//找左边区间
if(nums[mid] >= target){
right = mid - 1;
ans = mid;
}else {
left = mid + 1;
}
}else {
//找右边区间
if (nums[mid] > target){
right = mid - 1;
}else {
left = mid + 1;
ans = mid;
}
}
}
return ans;
}
}
第35题 搜索插入位置
二分查找
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1;
if (nums.length == 0) return 0;
if (nums.length == 1) return (nums[0] >= target) ? 0 : 1;
while (left <= right){
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
if (nums[mid] < target){
left = mid + 1;
}else {
right = mid - 1;
}
}
return left;
}
}
第36题 有效的数独
class Solution {
public boolean isValidSudoku(char[][] board) {
int[][] rows = new int[9][9];
int[][] columns = new int[9][9];
int[][][] subboxes = new int[3][3][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char c = board[i][j];
if (c != '.') {
int index = c - '0' - 1;
rows[i][index]++;
columns[j][index]++;
subboxes[i / 3][j / 3][index]++;
if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[i / 3][j / 3][index] > 1) {
return false;
}
}
}
}
return true;
}
}
第209题 长度最小的子数组
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
if(n == 0){
return 0;
}
if(n == 1) return nums[0] >= target ? 1 : 0;
//滑动窗口
int start = 0,end = 0;
int ans = Integer.MAX_VALUE;
int sum = 0;
while (end < n){
sum += nums[end];
while (sum >= target && start <= end){
sum -= nums[start];
ans = Math.min(ans, end - start + 1);
start++;
}
end++;
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
}
第977题 有序数组的平方
class Solution {
public int[] sortedSquares(int[] nums) {
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; ++i) {
ans[i] = nums[i] * nums[i];
}
Arrays.sort(ans);
return ans;
}
}