(笔试算法) Leetcode101之排序算法


重点掌握快排、堆排序、归并、桶排序等
下面排序算法直接复制Leetcode101里的

void quick_sort(vector<int> &nums, int l, int r) {
    if (l + 1 >= r) {
        return;
    }
    int first = l, last = r - 1, key = nums[first];
    while (first < last){
        while(first < last && nums[last] >= key) {
            --last;
        }
        nums[first] = nums[last];
        while (first < last && nums[first] <= key) {
            ++first;
        }
        nums[last] = nums[first];
    }
    nums[first] = key;
    quick_sort(nums, l, first);
    quick_sort(nums, first + 1, r);
}
// 分而治之
void merge_sort(vector<int> &nums, int l, int r, vector<int> &temp) {
    if (l + 1 >= r) {
        return;
    }
    // divide
    int m = l + (r - l) / 2;
    merge_sort(nums, l, m, temp);
    merge_sort(nums, m, r, temp);
    // conquer
    int p = l, q = m, i = l;
    while (p < m || q < r) {
        if (q >= r || (p < m && nums[p] <= nums[q])) {
            temp[i++] = nums[p++];
        } else {
            temp[i++] = nums[q++];
        }
    }
    for (i = l; i < r; ++i) {
        nums[i] = temp[i];
    }
}

215. 数组中的第K个最大元素 – 中等

返回数组中第k个大元素

输入: [3,2,1,5,6,4], k = 2
输出: 5
/**
	快排:每次会找到某个元素应该在的位置,如果此位置恰好是 nums.length - k 即是答案‘
	使用随机快排:时间复杂度接近O(n)
**/
class Solution {
    public int findKthLargest(int[] nums, int k) {
    	int location = nums.length - k;		// 第k大元素应该数组中的位置
    	int l = 0, r = nums.length - 1;	
    	while(l < r) {     // l <= r 快排会越界  
    		int mid = quickFind(nums, l, r);
    		if (mid > location) r = mid - 1;
    		else if (mid < location) l = mid + 1;
    		else return nums[mid];
    	}
    	return nums[location];
    }

    // 快速找到l应该在数组中的位置
	private int quickFind(int[] nums, int l, int r) {
		int loc = nums[l];
		int low = l + 1, high = r; 
		while (true) { // 寻找loc位置
			while(nums[low] <= loc && low < r) ++low;
    		while(nums[high] >= loc && high > l) --high;
    		if(low >= high) break;
            swap(nums, low, high);
		}
		swap(nums, l, high);
		return high;
	}

	public void swap(int[] nums, int l, int r) {
		int temp = nums[l];
		nums[l] = nums[r];
		nums[r] = temp;
	}
}

/**
	堆排序: 时间复杂度O(nlogn)
    	初始构造长度 nums.length 的大根堆
        每次移除一个元素,堆长度相应-1,一共移除 k-1 次, 此时堆顶元素就是第k大值
	// 注:如果k超过 1/2 数组,可以找第 nums.length - k 小元素
**/
class Solution {
    public int findKthLargest(int[] nums, int k) {
    	int heapSize = nums.length;
    	buildTopHeap(nums, heapSize);
    	for (int i = nums.length - 1; i > nums.length - k; --i) {
    		swap(nums, 0, i);
    		findMax(nums, 0, --heapSize);
    	}
    	return nums[0];
    }

	// 从 heapSize/2 上浮
	private void buildTopHeap(int[] nums, int heapSize) {
		for (int i = heapSize/2; i >= 0; --i) {
			findMax(nums, i, heapSize);
		}
	}

	private void findMax(int[] nums, int top, int heapSize) {
		int lChild = 2 * top + 1, rChild = 2 * top + 2, maxIndex = top;
		if (lChild < heapSize && nums[lChild] > nums[top]) maxIndex = lChild;
		if (rChild < heapSize && nums[rChild] > nums[maxIndex]) maxIndex = rChild;
		if (maxIndex != top) {
			swap(nums, top, maxIndex);
			findMax(nums, maxIndex, heapSize);
		}
	}

	private void swap(int[] nums, int top, int maxIndex) {
		int temp = nums[top];
		nums[top] = nums[maxIndex];
		nums[maxIndex] = temp;	
	}
}

347. 前 K 个高频元素 – 中等

返回数组中频率出现做多次数的前k个元素。 (多个答案返回任意一个)

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
/**
	掌握如何实现桶排序
	思路:优先选择频率较大的桶中的元素。
**/
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
    	Map<Integer, Integer> map = new HashMap<>();
    	
    	int maxSize = 0;
    	for (int i = 0; i < nums.length; i++) {
			int cur = nums[i];
			map.put(cur, map.getOrDefault(cur, 0) + 1);
			maxSize = Math.max(maxSize, map.get(cur));
		}
    	
    	List<Integer>[] buckerLists = new ArrayList[maxSize + 1];
    	for (int key : map.keySet()) {
    		int score = map.get(key);
    		if (buckerLists[score] == null) buckerLists[score] = new ArrayList<>();
    		buckerLists[score].add(key);
    	}
    	
    	int[] res = new int[k];
    	int idx = k-1;
    	for (int i = buckerLists.length - 1; i >= 0; --i) {
			if (buckerLists[i] == null) continue;
			for (int j = 0; j < buckerLists[i].size(); j++) {
				res[idx--] = buckerLists[i].get(j);
				if (idx < 0) break;
			}
			if (idx < 0) break;
		}
    	return res;
    }
}

451. 根据字符出现频率排序 – 中等

对字符串s按照字符频率降序排序,返回任何一个即可。

输入: s = "tree"
输出: "eert"
解释: 'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。
/**
	桶排序:
	排序:
	也可以用Collection集合对key进行排序:
    	List<Character> list = new ArrayList<Character>(map.keySet());
        Collections.sort(list, (a, b) -> map.get(b) - map.get(a));
    这样效率低
**/
class Solution {
    public String frequencySort(String s) {
    	Map<Character, Integer> map = new HashMap<>();
    	int max = 0;
    	for (int i = 0; i < s.length(); i++) {
    		char c = s.charAt(i);
			map.put(c, map.getOrDefault(c, 0) + 1);
			max = Math.max(max, map.get(c));
		}
    	List<Character>[] bucket = new ArrayList[max + 1];
    	for(char key : map.keySet()) {
    		int size = map.get(key);
    		if (bucket[size] == null) bucket[size] = new ArrayList<>();
    		bucket[size].add(key);
    	}
    	StringBuilder sb = new StringBuilder();
    	for (int i = bucket.length - 1; i > 0; --i) {
			if (bucket[i] == null) continue;
			for (char c : bucket[i]) {
				int size = i;
				while (size-- != 0) sb.append(c);
			}
		}
    	return new String(sb);
    }
}

75. 颜色分类 – 中等

原地对三个颜色排序,使得相同颜色相邻,每个数字代表一种颜色。

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
/**
	单指针:需要两次遍历,第一次把0放到最前面,第2次把1放到最前面。
	双指针:一次遍历,只需要把0放前面,2放后面即可。
**/
class Solution {
    public void sortColors(int[] nums) {
    	int p0 = 0, p2 = nums.length - 1;
    	for (int i = 0; i < nums.length; i++) {
            if(i > p2) break;
			if (nums[i] == 0 && i > p0) swap(nums, i--, p0++);
			else if (nums[i] == 2 && i < p2) swap(nums, i--, p2--);
		}
    }

    private void swap(int[] nums, int i, int j) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值