【leetcode算法面试】leetcode题目4-数组

题号题目说明
1Two Sum  两数之和暴利 / map查找
9Palindrome Number  验证回文数字 
11Container With Most Water 装最多水的容器
26Remove Duplicates from Sorted Array 有序数组中去除重复项
27Remove Element  移除元素
33Search in Rotated Sorted Array 在旋转有序数组中搜索二分搜索
34Find First and Last Position of Element in Sorted Array 搜索一个范围二分搜索
35Search Insert Position  搜索插入位置二分搜索
41First Missing Positive 首个缺失的正数
42Trapping Rain Water 收集雨水
56Merge Intervals 合并区间
59Spiral Matrix II 螺旋矩阵之二
66Plus One 加一运算
80Remove Duplicates from Sorted Array II 有序数组中去除重复项之二
81Search in Rotated Sorted Array II在旋转有序数组中搜索之二
84Largest Rectangle in Histogram 直方图中最大的矩形
88Merge Sorted Array 合并排序的数组
153Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值
154Find Minimum in Rotated Sorted Array II 寻找旋转有序数组的最小值之二
167Two Sum II - Input array is sorted 两数之和之二 - 输入数组有序
169Majority Element 求众数


1. [LeetCode] Two Sum  两数之和

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{}
}

9. Palindrome Number  验证回文数字 

      可以使用原反转与原来数值对比,注意的情况,负数直接false,最后一位是0情况也是false,还有溢出的情况

11. Container With Most Water 装最多水的容器

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
}

26. Remove Duplicates from Sorted Array 有序数组中去除重复项

      使用快慢指针来记录遍历的坐标,最开始时两个指针都指向第一个数字,如果两个指针指的数字相同,则快指针向前走一步,如果不同,则两个指针都向前走一步,这样当快指针走完整个数组后,慢指针当前的坐标加1就是数组中不同数字的个数

class Solution {
public:
    int removeDuplicates(vector<int>& 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;
    }
};


// go语言
func removeDuplicates(nums []int) int {
	var n = len(nums)
	if n <= 1 {
		return n
	}
	var slow int

	for fast := 1; fast < n; fast++ {
		if nums[slow] != nums[fast] {
			slow++
			nums[slow] = nums[fast]
		}
	}

	return slow+1
}

27. [LeetCode] Remove Element  移除元素

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<int>& nums, int val) {
        int res = 0;
        for (int i = 0; i < nums.size(); ++i) {
            if (nums[i] != val) nums[res++] = nums[i];
        }
        return res;
    }
};

33. Search in Rotated Sorted Array 在旋转有序数组中搜索

    关键在于获得了中间数后,判断下面要搜索左半段还是右半段

  • 如果中间的数小于最右边的数,则右半段是有序的
  • 若中间数大于最右边数,则左半段是有序的,
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
}

34. Find First and Last Position of Element in Sorted Array 搜索一个范围

    限定了时间复杂度为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
}

35. [LeetCode] Search Insert Position  搜索插入位置

    遍历一遍原数组,若当前数字大于或等于目标值,则返回当前坐标,如果遍历结束了,说明目标值比数组中任何一个数都要大,则返回数组长度n即可

class Solution {
public:
    int searchInsert(vector<int>& 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<int>& 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
}

41. First Missing Positive 首个缺失的正数

      利用正整数与下标之间的关系,假设如果现在的数组里有4个数,分别是1,2,4,5,那么,如果他们按照顺序排列起来我们就可以直接从头到尾扫一遍,通过比较nums[i] 和 下标i的关系,就知道哪个正数缺失,当第一次出现nums[i] != i+1时,就说明i+1是第一个缺失的正整数。

func firstMissingPositive(nums []int) int {
	var n = len(nums)
	for i:=0; i<n; i++ {
		for nums[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<n; i++ {
		if nums[i] != i+1 {
			return i+1
		}
	}
	return n+1
}

42. Trapping Rain Water 收集雨水

  • 如果较小值是left指向的值,则从左向右扫描

  • 如果较小值是right指向的值,则从右向左扫描

  • 若遇到的值比当较小值小,则将差值存入结果

  • 如遇到的值大,则重新确定新的窗口范围

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
}

56. Merge Intervals 合并区间

  • 起始位置和结束位置分别存到了两个不同的数组starts和ends中,然后分别进行排序
  • 判断不连续就加入结果中
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<n; i++ {
		starts[i] = intervals[i].Start
		ends[i] = intervals[i].End
	}
	sort.Ints(starts)
	sort.Ints(ends)
	for i:=0; i<n; i++ {
		if i==n-1 || starts[i+1] > ends[i] {
			res = append(res, Interval{starts[s], ends[i]})
			s = i + 1
		}
	}
	return res
}

59. Spiral Matrix II 螺旋矩阵之二

func generateMatrix(n int) [][]int {
	var res = make([][]int, 0)
	for i:=0; i<n; i++ {
		var temp = make([]int, n)
		res = append(res, temp)
	}
	var up, down, left, right, val = 0, n - 1, 0, n-1, 1
	for {
		for j:=left; j<=right; j++ {
			res[up][j] = val
			val++
		}
		up++
		if up > down {break}
		for i:=up; i<=down; i++ {
			res[i][right] = val
			val++
		}
		right--
		if right<left {break}
		for j:=right; j>=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
}

66. Plus One 加一运算

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
}

80. Remove Duplicates from Sorted Array II 有序数组中去除重复项之二

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
}

81. Search in Rotated Sorted Array II在旋转有序数组中搜索之二

    出现来面两种情况,[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
}

84. Largest Rectangle in Histogram 直方图中最大的矩形

     局部峰值,然后向前遍历所有的值,算出共同的矩形面积,每次对比保留最大值

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
}

88. Merge Sorted Array 合并排序的数组

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--
	}
}

153. Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值

     中间那个数,然后和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])
}

154. Find Minimum in Rotated Sorted Array II 寻找旋转有序数组的最小值之二

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))
}

167. Two Sum II - Input array is sorted 两数之和之二 - 输入数组有序

    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}
}

169. Majority Element 求众数

func majorityElement(nums []int) int {
	var res, cnt = 0, 0
	for i:=0; i<len(nums); i++ {
		if cnt == 0 {
			res = nums[i]
			cnt++
		} else {
				if nums[i] == res {
					cnt++
				} else {
					cnt--
				}
		}
	}
	return res
}

347. Top K Frequent Elements

    前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.

2. leetcode 约瑟夫问题

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


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<n; i++) {
		pN[i] = i + 1;
	}

	yueSeFu(pN, n, m);
	return 0;
}

3. leetcode KMP

求模式 a b a a b c a c的next函数的算法:
因为已知next(1)=0,只要找出next(j+1)与next(j)之间的关系,就可以求出模式串所有next。
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">next初始算法::::</span>
(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) 必然有<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">p(1)...p(k-1)p(k) = p(j-k+1)...p(j-1)p(j)  next[j+1] = next[j] + 1 = k +1</span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">         若不等   </span>
void get_next(sstring T, int &next[])
{
  //求模式串T的next函数值并存入数组next。
  j=1; k=next[j]=0;
  while (j<T[0])  {  //计算next(j)从next(2)到next(T[0]),T[0]是T的长度
                    //但并不意味着只循环m-1次,因为在循环体中j的值可能不发生变化
    if (k==0||T[j]==T[k])// 没有重叠真子串和(有重叠真子串但T[j]==T[k])时//都应该得出next(j+1)的值
      next[++j]=++k;
    else k=next(k);//否则,得不出next(j+1)的值,所以j不变,k退回到next(k),重复匹配。
}
利用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

统计N以内素数的个数

(素数:只能被1和自身整除的自然数,0 1 除外)

暴力法

埃筛法

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值