题号 | 题目 | 说明 |
1 | Two Sum 两数之和 | 暴利 / map查找 |
9 | Palindrome Number 验证回文数字 | |
11 | Container With Most Water 装最多水的容器 | |
26 | Remove Duplicates from Sorted Array 有序数组中去除重复项 | |
27 | Remove Element 移除元素 | |
33 | Search in Rotated Sorted Array 在旋转有序数组中搜索 | 二分搜索 |
34 | Find First and Last Position of Element in Sorted Array 搜索一个范围 | 二分搜索 |
35 | Search Insert Position 搜索插入位置 | 二分搜索 |
41 | First Missing Positive 首个缺失的正数 | |
42 | Trapping Rain Water 收集雨水 | |
56 | Merge Intervals 合并区间 | |
59 | Spiral Matrix II 螺旋矩阵之二 | |
66 | Plus One 加一运算 | |
80 | Remove Duplicates from Sorted Array II 有序数组中去除重复项之二 | |
81 | Search in Rotated Sorted Array II在旋转有序数组中搜索之二 | |
84 | Largest Rectangle in Histogram 直方图中最大的矩形 | |
88 | Merge Sorted Array 合并排序的数组 | |
153 | Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值 | |
154 | Find Minimum in Rotated Sorted Array II 寻找旋转有序数组的最小值之二 | |
167 | Two Sum II - Input array is sorted 两数之和之二 - 输入数组有序 | |
169 | Majority Element 求众数 |
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
暴力搜索的方法是遍历所有的两个数字的组合,然后算其和,这样虽然节省了空间,但是时间复杂度高。为了提高时间的复杂度,需要用空间来换,可以使用map存数据,首先遍历一遍存入map,再次遍历使用key查找,而且注意的时不能是同一个下标。
func twoSum(nums []int, target int) []int {
var mapNumbers = make(map[int]int)
for i := 0; i < len(nums); i++ {
mapNumbers[nums[i]] = i
}
for i := 0; i < len(nums); i++ {
another := target - nums[i]
if val, ok := mapNumbers[another]; ok {
if i == val {
continue
}
return []int{i, val}
}
}
return []int{}
}
可以使用原反转与原来数值对比,注意的情况,负数直接false,最后一位是0情况也是false,还有溢出的情况
func maxArea(height []int) int {
var left, right, max = 0, len(height) - 1, 0
for left < right {
var cur int
if height[left] < height[right] {
cur = height[left]
left++
} else {
cur = height[right]
right--
}
curArea := cur * (right - left + 1)
if max < curArea {
max = curArea
}
}
return max
}
使用快慢指针来记录遍历的坐标,最开始时两个指针都指向第一个数字,如果两个指针指的数字相同,则快指针向前走一步,如果不同,则两个指针都向前走一步,这样当快指针走完整个数组后,慢指针当前的坐标加1就是数组中不同数字的个数
class Solution {
public:
int removeDuplicates(vector& nums) {
if (nums.empty()) return 0;
int pre = 0, cur = 0, n = nums.size();
while (cur < n) {
if (nums[pre] == nums[cur]) ++cur;
else nums[++pre] = nums[cur++];
}
return pre + 1;
}
};
Given an array and a value, remove all instances of that value in place and return the new length.
The order of elements can be changed. It doesn't matter what you leave beyond the new length.
定义一个变量用来计数,遍历原数组,如果当前的值和给定值不同,我们就把当前值覆盖计数变量的位置,并将计数变量加1
class Solution {
public:
int removeElement(vector& nums, int val) {
int res = 0;
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] != val) nums[res++] = nums[i];
}
return res;
}
};
关键在于获得了中间数后,判断下面要搜索左半段还是右半段
func search(nums []int, target int) int {
var left, right = 0, len(nums) - 1
for left <= right {
var mid = (left + right) / 2
if nums[mid] == target {
return mid
} else if nums[mid] > nums[right] { // left
if target >= nums[left] && target < nums[mid] {
right = mid - 1
} else {
left = mid + 1
}
} else { // right
if target > nums[mid] && target <= nums[right] {
left = mid + 1
} else {
right = mid - 1
}
}
}
return -1
}
限定了时间复杂度为O(logn),这是典型的二分查找法的时间复杂度。思路是首先对原数组使用二分查找法,找出其中一个目标值的位置,然后向两边搜索找出起始和结束的位置
使用两次二分查找法,第一次找到左边界,第二次调用找到右边界即可
主要在于处理右边界问题
func searchRange(nums []int, target int) []int {
var left, right = 0, len(nums) - 1
var res []int
if len(nums) <= 0 {
return []int{-1, -1}
}
for left < right {
var mid = (left + right) / 2
if nums[mid] < target {
left = mid + 1
} else {
right = mid
}
}
if nums[left] != target {
return []int{-1, -1}
}
fmt.Printf("left: %v\n", left)
res = append(res, left)
right = len(nums)
for left < right {
var mid = (left + right) / 2
fmt.Printf("mid: %v\n", mid)
if nums[mid] > target {
right = mid
} else {
left = mid + 1
}
}
res = append(res, right-1)
return res
}
遍历一遍原数组,若当前数字大于或等于目标值,则返回当前坐标,如果遍历结束了,说明目标值比数组中任何一个数都要大,则返回数组长度n即可
class Solution {
public:
int searchInsert(vector& nums, int target) {
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] >= target) return i;
}
return nums.size();
}
};
二分搜索法
class Solution {
public:
int searchInsert(vector& nums, int target) {
if (nums.back() < target) return nums.size();
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid;
}
return right;
}
};
func searchInsert(nums []int, target int) int {
var left, right = 0, len(nums) - 1
for left <= right {
var mid = (left + right) / 2
if nums[mid] == target {
return mid
} else if nums[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return left
}
func firstMissingPositive(nums []int) int {
var n = len(nums)
for i:=0; i 0 && nums[i] <= n && nums[i] != i+1 && nums[nums[i]-1] != nums[i] {
nums[i], nums[nums[i]-1] = nums[nums[i]-1], nums[i]
}
}
for i:=0; i
func trap(height []int) int {
var left, right, res = 0, len(height)-1, 0
var min = func(a, b int) int {
if a < b {
return a
}
return b
}
for left < right {
var min = min(height[left], height[right])
if height[left] == min {
left++
for left < right && height[left] < min {
res += min - height[left]
left++
}
} else {
right--
for left < right && height[right] < min {
res += min - height[right]
right--
}
}
}
return res
}
func merge(intervals []Interval) []Interval {
var n, s = len(intervals), 0
var res, starts, ends = make([]Interval, 0), make([]int, n), make([]int, n)
for i:=0; i ends[i] {
res = append(res, Interval{starts[s], ends[i]})
s = i + 1
}
}
return res
}
func generateMatrix(n int) [][]int {
var res = make([][]int, 0)
for i:=0; i down {break}
for i:=up; i<=down; i++ {
res[i][right] = val
val++
}
right--
if right=left; j-- {
res[down][j] = val
val++
}
down--
if down < up {break}
for i:=down; i>=up; i-- {
res[i][left] = val
val++
}
left++
if left > right {break}
}
return res
}
func plusOne(digits []int) []int {
for i:=len(digits)-1; i>=0; i-- {
if digits[i] == 9 {
digits[i] = 0
} else {
digits[i] += 1
return digits
}
}
if digits[0] == 0 {
digits = append([]int{1}, digits...)
}
return digits
}
Follow up for "Remove Duplicates":
What if duplicates are allowed at most twice?For example,
Given sorted array A =[1,1,1,2,2,3]
,Your function should return length =
5
, and A is now[1,1,2,2,3]
.
使用两个指针prev和curr,判断A[curr]是否和A[prev]、A[prev-1]相等,如果相等curr指针继续向后遍历,直到不相等时,将curr指针指向的值赋值给A[prev+1],这样多余的数就都被交换到后面去了。最后prev+1值就是数组的长度
func removeDuplicates(nums []int) int {
n := len(nums)
if n <= 2 {
return n
}
var (
pre = 1
cur = 2
)
for i := cur; i < n; i++ {
if nums[cur] == nums[pre] && nums[cur] == nums[pre-1] {
cur++
} else {
pre += 1
nums[pre] = nums[cur]
cur += 1
}
}
return pre + 1
}
出现来面两种情况,[3 1 1] 和 [1 1 3 1],对于这两种情况中间值等于最右值时,目标值3既可以在左边又可以在右边,那怎么办么,对于这种情况其实处理非常简单,只要把最右值向左一位即可继续循环,如果还相同则继续移,直到移到不同值为止
func search(nums []int, target int) bool {
var left, right = 0, len(nums) - 1
for left <= right {
var mid = (left + right) / 2
if nums[mid] == target {
return true
} else if nums[mid] < nums[right] {
if nums[mid] < target && nums[right] >= target {
left = mid + 1
} else {
right = mid - 1
}
} else if nums[mid] > nums[right] {
if nums[left] <= target && nums[mid] > target {
right = mid - 1
} else {
left = mid + 1
}
} else {
right--
}
}
return false
}
func largestRectangleArea(heights []int) int {
var res = 0
var min = func(a, b int) int {
if a < b {
return a
}
return b
}
var max = func(a, b int) int {
if a > b {
return a
}
return b
}
for i := 0; i < len(heights); i++ {
if i+1 < len(heights) && heights[i] <= heights[i+1] {
continue
}
var minH = heights[i]
for j := i; j >= 0; j-- {
minH = min(minH, heights[j])
var area = (i - j + 1) * minH
res = max(res, area)
}
}
return res
}
func merge(nums1 []int, m int, nums2 []int, n int) {
var i, j, k = m - 1, n - 1, m + n - 1
for i >= 0 && j >= 0 {
if nums1[i] > nums2[j] {
nums1[k] = nums1[i]
i--
} else {
nums1[k] = nums2[j]
j--
}
k--
}
for j >= 0 {
nums1[k] = nums2[j]
k--
j--
}
}
中间那个数,然后和left指的数比较,如果中间的数大,则继续二分查找右半段数组,反之查找左半段。终止条件是当左右两个指针相邻,返回小的那个。
func findMin(nums []int) int {
var left, right = 0, len(nums) - 1
if right < 0 {return 0}
if right == 0 {return nums[0]}
if nums[left] < nums[right] {
return nums[left]
}
var min = func(a, b int) int {
if a < b {return a}
return b
}
for left < right-1 {
var mid = (left + right) / 2
if nums[left] < nums[mid] {
left = mid
} else {
right = mid
}
}
return min(nums[left], nums[right])
}
func findMin(nums []int) int {
var left, right = 0, len(nums) - 1
if right < 0 {return 0}
var res = nums[0]
var min = func(a, b int) int {
if a < b {return a}
return b
}
for left < right-1 {
var mid = (left + right) / 2
if nums[left] < nums[mid] {
res = min(res, nums[left])
left = mid+1
} else if nums[left] > nums[mid]{
res = min(res, nums[right])
right = mid
} else {
left++
}
}
return min(nums[left], min(nums[right], res))
}
O(n)的解法,left指向开头,right指向末尾,然后向中间遍历,如果指向的两个数相加正好等于target的话,直接返回两个指针的位置即可,若小于target,left右移一位,若大于target,right左移一位
func twoSum(numbers []int, target int) []int {
var left, right = 0, len(numbers) - 1
for left < right {
var sum = numbers[left] + numbers[right]
if sum == target {
return []int{left+1, right+1}
} else if sum > target {
right--
} else {
left--
}
}
return []int{-1, -1}
}
func majorityElement(nums []int) int {
var res, cnt = 0, 0
for i:=0; i
前K个高频元素
Given a non-empty array of integers, return the k most frequent elements.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]
Example 2:
Input: nums = [1], k = 1 Output: [1]
Note:
- You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
- Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
#include
#include
#include
void yueSeFu(int a[], int n, int m) {
if (a==NULL || n<=0) return;
int count = n;
int i = 0; //n
int j = 0; //m
while (count != 0) {
if (a[i] != 0) {
j++;
if (j%m == 0) {
j = 0;
printf("%d\n", a[i]);
a[i] = 0;
count--;
}
}
i++;
if (i%n == 0)
i = 0;
}
}
int main()
{
int n, m, i;
scanf("%d %d", &n, &m);
int *pN = (int *)malloc(sizeof(int) * (n));
if (pN == NULL)
exit(-1);
for (i=0; i
求模式 a b a a b c a c的next函数的算法:
因为已知next(1)=0,只要找出next(j+1)与next(j)之间的关系,就可以求出模式串所有next。
next初始算法::::
(1)next[j] = 0 j=1
(2)设next[j]=k, 于是有p(1)...p(k-1) = p(j-k+1)...p(j-1)
若p(k) = p(j) 必然有p(1)...p(k-1)p(k) = p(j-k+1)...p(j-1)p(j) next[j+1] = next[j] + 1 = k +1
若不等
void get_next(sstring T, int &next[])
{
//求模式串T的next函数值并存入数组next。
j=1; k=next[j]=0;
while (j
利用next值表进行匹配的过程:
假设以i和j分别指示主串和模式串中正待比较的字符,若si=tj ,则i和j分别增1,否则,i不变,而j退回到next[j]的位置再比较,若j退回到值为0(即模式的第一个字符失配),则将模式继续向右滑动一个位置,即从主串的下一个字符si+1起和模式重新开始匹配。
int index_KMP(sstring s, sstring t, int pos)
{
//利用模式串的next函数求t在主串s中第pos个字符之后的位置的KMP算法,
//t非空,1<=pos<=strlength(s)
i=pos; j=1;
while(i<=s[0]&&j<=t[0])
{
if (j==0||s[i]==t[j]){++i;++j;}
else j=next[j];
}
if (j>t[0]) return i-t[0];
else return 0;
}//index_kmp