数组 -- 算法

二分查找

循环遍历实现,重要的是了解循环不变量——通过在 [l...r] 这个范围中寻找target,这样就不会搞不清l和r如何赋值的边界条件了。

int binarySearch(int[] arr, int n, int target) {
    int l = 0, r = n - 1;   // 在[l...r]的范围里寻找target 【循环不变量 -- 有一个声明是不会发生变化的】
    while(l <= r) {
        int mid = l + ( r-l)/2;
        if(target == arr[mid])
            return mid;
        if(target > arr[mid]){
            l = mid + 1;    // target 在 [mid+1...r] 中
        }else{
            r = mid - 1;     // target 在 [l...mid-1] 中
        }
    }
    return -1;    // 没有找到
}

// 思考: 如果在 [l...r)范围中寻找target,应该怎么修改代码呢?

二分查找比较难想的题目: 33. 搜索旋转排序数组 

moveZeros

体会[0...k) 前闭后开范围的用法,nums[k++]=nums[i]。循环不变量为[0...k)始终为非零元素,k初始值为0,该范围开始没有非零元素。

// [0,1,2,0,5] --> [1,2,5,0,0]
void moveZeros(int[] nums){
    // nums中,[0...k)的元素均为非零元素
    int k = 0;  // [0...k)为空

    // 遍历到第i个元素后,保证[0...i]中所有非0元素
    // 都按照顺序排列在[0...k)中
    // 同时,[i...k]为0
    for(int i=0; i<nums.size(); i++){
        if(nums[i]!=0){
            if(i==k)            // 优化代码,防止不必要的交换
                k++; continue;
            swap(nums, i, k++);
        }
    }
}

滑动窗口

数组中一个窗口,通过移动左右边界始终满足某个条件。

leetcode例题:
3 最长不重复子串
209 最少和大于s的数
438 find all anagrams in a string
76 minimum window substring

// 209 Minimum Size Subarray Sum
int minSubArrayLen(int s, int[] nums){
	int lo = 0;
	int hi = -1;  // [lo..hi]
	int min = nums.length+1;
	int sum = 0;
	while (hi+1 < nums.length) {   // [2,5,7,12]   10
		if (sum < s) {
			hi++;
			sum += nums[hi];
		}
		while (lo < nums.length && sum >= s) {
			min = Math.min(min, hi - lo + 1);
			sum -= nums[lo++];
		}
	}
	return min==nums.length+1?0:min;

}

// 3 Longest Substring Without Repeating Characters
public int lengthOfLongestSubstring(String s){
	char[] chs = s.toCharArray();
	HashSet<Character> set = new HashSet<>();
	int lo = 0;
	int hi = -1;
	int max = 0;
	while (hi + 1 < chs.length && lo < chs.length) {
		if (!set.contains(chs[hi + 1])) {
			hi++;
			set.add(chs[hi]);
			max = Math.max(max, hi - lo + 1);
		} else {
			set.remove(chs[lo--]);
		}

}

快速排序

int[] quickSort(int[] nums){
    if(nums==null || nums.length=1) return nums;
    quickSort_r(nums, 0, nums.length-1);
    return nums;
}
void quickSort_r(int[] nums, int left, int right){
    if(left>=right) return;
    int idx = partition(nums, left, right);
    quickSort_r(nums, left, idx-1);
    quickSort_r(nums, idx+1, right);
}

// 1路快排
// 3 1 4 6 7 5
int partition_1(int[] nums, int left, int right){
    // [left,i)<pivot 
    int pivot = nums[right];
    int i=left;
    for(int j=left, j<right, j++){
        if(nums[j]<pivot){
            swap(nums, i, j);
            i++;
        }
    }
    swap(nums, i, right);
    return i;
}
// 2路快排
void partition_2(int[] nums, int left, int right){
    // [left,i)<pivot [i,j]-处理中 (j,right]>pivot
    int pivot = nums[right];
    int i=left,j=right-1;
    while(i<=j){
        if(nums[i]>pivot){
            swap(nums,i,j);
            j--;     // i不变,交换后i的位置可能还会>pivot
        }else{
            i++;
        }
    }
    swap(nums,i,right);
    return i;
}

三路快排

func quickSort(nums []int) []int {

	quickSort_r(nums, 0, len(nums)-1)
	return nums
}

func quickSort_r(nums []int, l int, r int) {
	if nums == nil || len(nums) == 1 {
		return
	}
	low, high := partition(nums, l, r)
	if low > l {
		quickSort_r(nums, l, low-1)
	}
	if high < r{
		quickSort_r(nums, high+1, r)
	}
}

// 1,1,1,2,2,0,0,2,1
// 三路快排,优化重复值
func partition_3(nums []int, l int, r int) (int, int) {
	// l,low)<pivot [low,high]==pivot (high,r]>pivot
	pivot := nums[r]
	low, high := l, r
	for i := l; i <= high; {
		if nums[i] < pivot {
			swap(nums, i, low)
			low++
			i++
		} else if nums[i] > pivot {
			swap(nums, i, high)
			high--
		} else {
			i++
		}
	}
	return low, high
}

func swap(nums []int, i, j int) {
	tmp := nums[i]
	nums[i] = nums[j]
	nums[j] = tmp
}

无序数组选择最小的k个数

    大小为k的大顶堆,堆顶是k个数里面最大的,将数组中的元素一次推入,只要比堆顶元素小的,就将堆顶元素出队

PriorityQueue<Freq>    Java库是小顶堆实现的优先队列。

int parent(int index)        (index-1) / 2

int leftChild(int index)     2*index+1

int rightChild(int index)    2*index+2

堆排序: 最关键的接口:void heapify(int[] arr, int n, int k) ; 

// 从第K个节点开始siftdown到数组末尾 
// 2k+1 2k+2    (n-1)/2
private void heapify(int[] arr, int n, int k){
	while(2*k+1<n){
		int j = 2*k+1;
		if(j+1<n && arr[j+1]>arr[j]){
			j = j+1;
		}
		if(arr[k]>arr[j]) break;
		swap(arr, k, j);
		k = j;
	}
}
// 递归
private void heapify(int[] arr, int n, int k){
	if(k>=n) return;
	int j = k;
	if(2*k+1<n && arr[2*k+1]>arr[j]) j=2*k+1;
	if(2*k+2<n && arr[2*k+2]>arr[j]) j=2*k+2;
	if(j!=k){
		swap(arr, j, k);
		heapify(arr, n, j);
	}
}

// 从小到大排序  大顶堆
void heapSort(int arr){
	int n = arr.length;
	// 堆化
	for(int i=(n-2)/2; i>=0; i--){
		heapify(arr, n, i);
	}
	// 原地交换
	for(int i=n-1; i>0; i--){
		swap(arr, 0, i);
		heapify(arr, i, 0);
	}
}

跳跃游戏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值