Open xiedaxia1hao opened 3 years ago
Given an integer array nums and an integer k, return the kth largest element in the array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
这道题让我们求一个数组里面第k大的数字。
比如 [1, 3, 5, 2, 6, 4]
这个数组中,让我们求k=2大的数的话,最容易想到的方法是把整个数组先sort一下,然后 return nums[arr.length-k+1]
即可。
这种做法的复杂度是O(nlgn),可以优化一下吗?
我们可以尝试一下使用minHeap:
我们用数组 [1, 3, 5, 2, 6, 4]
,k=4 来举个例子:
[1, 3, 5, 2]
[1, 3, 5, 2, 6]
。但是因为我们当前heap的size是5,我们需要除掉一个多余的数字。因为是最小堆,我们要除掉的是1。此时我们的heap就是:[3, 5, 2, 6]
[3, 5, 2, 6, 4]
,除掉当前heap中最小的元素,得到: [3, 5, 6, 4]
[3, 5, 6, 4]
就是原数组[1, 3, 5, 2, 6, 4]
里最大的4个数字,这个时候,heap的顶端元素 3
就是最大的4哥数字中,最小的一个,即第4大的元素。这样做的话,时间复杂度是多少呢?
当然了,这题用maxHeap也可以,我们把所有的元素放到heap里,我们需要poll出去k-1个元素,然后此时heap的root就是我们的kth largest element了。 但是这样的话,空间复杂度就大了,因为我们最大要保存n个元素,而minHeap可以保证我们的size是 <= k的。
代码如下:
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for(int num : nums) {
minHeap.offer(num);
if(minHeap.size() > k) {
minHeap.poll();
}
}
return minHeap.peek();
}
}
这里介绍一个quick select的方法,可以把复杂度优化到O(n),虽然和这个专题里的pattern没什么关系,但是因为这题实在是经典,quick select的方法也是需要掌握的。
class Solution {
public int findKthLargest(int[] nums, int k) {
int n = nums.length;
int left = 0, right = n-1;
Random rand = new Random(0);
while(left <= right) {
int chosenPivotIndex = rand.nextInt(right-left+1) + left;
int finalPivotIndedx = partition(nums, left, right, chosenPivotIndex);
if(finalPivotIndedx == n-k) {
return nums[finalPivotIndedx];
} else if(finalPivotIndedx < n-k) {
left = finalPivotIndedx+1;
} else {
right = finalPivotIndedx-1;
}
}
return -1;
}
public int partition(int[] nums, int left, int right, int pivotIndex) {
int pivotValue = nums[pivotIndex];
swap(nums, right, pivotIndex);
int i = left;
for(int j = left; j < right; j++) {
if(nums[j] < pivotValue) {
swap(nums, i, j);
i++;
}
}
swap(nums, i, right);
return i;
}
public void swap(int[] nums, int first, int second) {
int temp = nums[first];
nums[first] = nums[second];
nums[second] = temp;
}
}
Quick select的时间复杂度怎么算呢?
我们可以用递推式来想:
每一轮我们都会把我们的数组变成其中的一半,然后对于每一步来说,如果当前的数组长度为n,我们要做n-1次comparison来得到最终的答案,那我们最后的递推式就是:
T(n) = T(n/2) + (n-1)
具体的解法就是:
这道题让我们求最接近原点的k个点
这题和模版题一样,其实对于每个点我们可以直接算出来其与原地的距离,所以这题的解法和模版题的三种解法一致。下面把两种解法都放出来,复杂度也是一致的。
class Solution {
public int[][] kClosest(int[][] points, int k) {
PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a, b) -> (b[1] * b[1] + b[0] * b[0] - a[1] * a[1] - a[0] * a[0]));
for(int[] point : points) {
maxHeap.offer(point);
if(maxHeap.size() > k) {
maxHeap.poll();
}
}
int[][] res = new int[k][2];
for(int i = 0; i < res.length; i++) {
res[i] = maxHeap.poll();
}
return res;
}
}
Quick Select:
class Solution {
public int[][] kClosest(int[][] points, int k) {
int n = points.length;
int[][] res = new int[k][2];
int left = 0, right = n-1;
Random rand = new Random(0);
while(left <= right) {
int chosenPivotIndex = rand.nextInt(right-left+1) + left;
int finalPivotIndex = partition(points, left, right, chosenPivotIndex);
if(finalPivotIndex == k-1) {
for(int i = 0; i < k; i++) {
res[i] = points[i];
}
return res;
} else if(finalPivotIndex < k-1) {
left = finalPivotIndex + 1;
} else {
right = finalPivotIndex - 1;
}
}
return new int[0][2];
}
public int partition(int[][] points, int left, int right, int chosenPivotIndex) {
int[] pivotPoint = points[chosenPivotIndex];
int pivotToOriginDist = calculateDistance(pivotPoint);
swap(points, chosenPivotIndex, right);
int i = left;
for(int j = left; j < right; j++) {
if(calculateDistance(points[j]) < pivotToOriginDist) {
swap(points, i, j);
i++;
}
}
swap(points, i, right);
return i;
}
public int calculateDistance(int[] point) {
return point[0] * point[0] + point[1] * point[1];
}
public void swap(int[][] points, int first, int second) {
int[] temp = points[first];
points[first] = points[second];
points[second] = temp;
}
}
Given ‘N’ ropes with different lengths, we need to connect these ropes into one big rope with minimum cost. The cost of connecting two ropes is equal to the sum of their lengths.
这一题其实把上面几个example的case走一遍之后,就大概能理解怎么做了。
本质上就是一个贪心的思想,我们每次把长度最短的两根绳子相加,直到加到最后一根绳子。
既然每次我们都要把长度最短的两根绳子相加,我们可以维护一个minHeap:
res
里代码如下:
class ConnectRopes {
public static int minimumCostToConnectRopes(int[] ropeLengths) {
int res = 0;
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for(int length : ropeLengths) {
minHeap.offer(length);
}
while(minHeap.size() > 1) {
int newLength = minHeap.poll() + minHeap.poll();
res += newLength;
minHeap.offer(newLength);
}
return res;
}
}
设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。 请实现 KthLargest 类:
- KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
- int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。
class KthLargest {
PriorityQueue<Integer> minHeap;
int k;
public KthLargest(int k, int[] nums) {
this.minHeap = new PriorityQueue<>();
this.k = k;
for(int num : nums) {
minHeap.offer(num);
if(minHeap.size() > k) {
minHeap.poll();
}
}
}
public int add(int val) {
minHeap.offer(val);
while(minHeap.size() > k) {
minHeap.poll();
}
return minHeap.peek();
}
}
对于一些特定的top k的题目,使用heap的效率可能并不一定是最快的。有些题目由于会有一些隐藏的限制,可以进行进一步的优化。
比如让我们求top k frequency appeared characters,我们可以知道一个character最大的frequency就是nums.length,最小的就为1,在这样的constraints下,我们可以想到用bucket sort来进一步优化。
Given an integer array
nums
and an integerk
, return thek
most frequent elements. You may return the answer in any order. Constraints: 1 <= nums.length <= 10^5 k is in the range [1, the number of unique elements in the array]. It is guaranteed that the answer is unique. Follow up: Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
这题的思想和kth largest elements的思想是一样的,我们可以先用一个hashmap来保存所有的element和它们分别出现的次数,然后通过heap来处理找top k frequent的元素。这样的话,时间复杂度是O(nlgk),符合题目的要求 (O(nlgn))。
代码如下:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int num : nums) {
map.put(num, map.getOrDefault(num, 0)+1);
}
PriorityQueue<Map.Entry<Integer, Integer>> minHeap = new PriorityQueue<>((a, b) -> a.getValue()-b.getValue());
for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
minHeap.offer(entry);
if(minHeap.size() > k) {
minHeap.poll();
}
}
int[] res = new int[k];
for(int i = 0; i < res.length; i++) {
res[i] = minHeap.poll().getKey();
}
return res;
}
}
Time Complexity: O(N + N * logk) Space Complexity: O(N)
这题如果用quickselect也能做,但是实现上可能没有那么方便。
仔细读题后我们可以知道,一个数字的最大的出现频率无非就是array.length,所以我们可以尝试一下用bucket sort来求解,这样的话时间复杂度就是O(n):
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int num : nums) {
map.put(num, map.getOrDefault(num, 0)+1);
}
List<Integer>[] bucket = new List[nums.length+1];
for(int key : map.keySet()) {
int frequency = map.get(key);
if(bucket[frequency] == null) {
bucket[frequency] = new ArrayList<>();
}
bucket[frequency].add(key);
}
// add result to an array
int[] res = new int[k];
int j = 0;
for(int i = bucket.length-1; i >= 0; i--) {
if(bucket[i] != null) {
List<Integer> numWithFrequencyI = bucket[i];
for(int num : numWithFrequencyI) {
res[j++] = num;
}
if(j == k) break;
}
}
return res;
}
}
Given a string s, sort it in decreasing order based on the frequency of characters, and return the sorted string.
这题和上面一题本质上是一样的,只是上面一题我们sort的是数字,这一题改成character了。
我们可以用heap和bucket sort分别解一下:
class Solution {
public String frequencySort(String s) {
Map<Character, Integer> map = new HashMap<>();
for(char chr : s.toCharArray()) {
map.put(chr, map.getOrDefault(chr, 0)+1);
}
PriorityQueue<Map.Entry<Character, Integer>> maxHeap = new PriorityQueue<>((a, b) -> (b.getValue() - a.getValue()));
for(Map.Entry<Character, Integer> entry : map.entrySet()) {
maxHeap.offer(entry);
}
StringBuilder res = new StringBuilder();
while(!maxHeap.isEmpty()) {
Map.Entry<Character, Integer> charFrequencyPair = maxHeap.poll();
char chr = charFrequencyPair.getKey();
int frequency = charFrequencyPair.getValue();
for(int i = 0; i < frequency; i++) {
res.append(chr);
}
}
return new String(res);
}
}
用heap的解法的话,时间复杂度:O(DlgD), D代表string中的distinct character。最差的情况下,时间复杂度则为O(NlgN), N代表string的character的数量。
那如果用bucket sort的解法来解呢?
class Solution {
public String frequencySort(String s) {
Map<Character, Integer> map = new HashMap<>();
for(char chr : s.toCharArray()) {
map.put(chr, map.getOrDefault(chr, 0)+1);
}
List<Character>[] bucket = new List[s.length()+1];
for(char key : map.keySet()) {
int frequency = map.get(key);
if(bucket[frequency] == null) {
bucket[frequency] = new ArrayList<>();
}
bucket[frequency].add(key);
}
StringBuilder res = new StringBuilder();
for(int freq = bucket.length-1; freq >= 0; freq--) {
if(bucket[freq] != null) {
for(char key : bucket[freq]) {
for(int i = 0; i < freq; i++) {
res.append(key);
}
}
}
}
return new String(res);
}
}
时间复杂度就变为:O(n)
Given a sorted integer array
arr
, two integersk
andx
, return thek
closest integers tox
in the array. The result should also be sorted in ascending order. An integera
is closer tox
than an integerb
if:
|a - x| < |b - x|
, or|a - x| == |b - x|
anda < b
这题其实可以把所有的arr里的数放到一个minHeap里,排序的规则就是离点到x的距离越小,对应的优先级越高,如果有两个点到x的距离相等,那么index越小的优先级越高。
这题难点就是该怎么样写这个lambda表达式,仔细琢磨一下可以得到:
PriorityQueue<Integer> minHeap =
new PriorityQueue<>((a, b) -> (Math.abs(a-x) != Math.abs(b-x) ? Math.abs(a-x) - Math.abs(b-x) : a-b));
最后再sort一下就行了。
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>((a, b) -> (Math.abs(a-x) != Math.abs(b-x) ? Math.abs(a-x) - Math.abs(b-x) : a-b));
for(int num : arr) {
minHeap.offer(num);
}
List<Integer> res = new ArrayList<>();
for(int i = 0; i < k; i++) {
res.add(minHeap.poll());
}
Collections.sort(res);
return res;
}
}
如果我们这样做的话,上面一题的时间复杂度是O(nlgn + klgk)。
我们可以稍微优化一下,因为我们把所有的数都放到heap里面来了。如果我们先用binary search,找到该x原本应该在的位置,然后向左向右k个距离的一个区间就是我们答案出现的可能的区间了。我们可以对剩下的2k长度进行heap操作,这样可以做到一定程度上的优化。
优化后的时间复杂度:O(lgn + klgk)
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int index = binarySearch(arr, x);
int left = Math.max(0, index-k);
int right = Math.min(index+k, arr.length-1);
PriorityQueue<Integer> minHeap = new PriorityQueue<>((a, b) -> (Math.abs(a-x) != Math.abs(b-x) ? Math.abs(a-x) - Math.abs(b-x) : a-b));
for(int i = left; i <= right; i++) {
minHeap.offer(arr[i]);
}
List<Integer> res = new ArrayList<>();
for(int i = 0; i < k; i++) {
res.add(minHeap.poll());
}
Collections.sort(res);
return res;
}
public int binarySearch(int[] arr, int target) {
int lo = 0, hi = arr.length-1;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(arr[mid] == target) {
return mid;
} else if(arr[mid] > target) {
hi = mid-1;
} else {
lo = mid+1;
}
}
return hi;
}
}
当然,这题不用heap做可以更快。因为arr本身是sorted的,而本质上我们要找的是一个固定大小的区间,所以我们可以用collide pointer的方法。
分别初始化一个lo
和hi
指针,指向arr
的头和尾,哪个离x的距离越远,就把那根指针缩回来,直到hi-lo+1=k
。
时间复杂度就是O(n)
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int lo = 0, hi = arr.length-1;
while(hi-lo+1 > k) {
if(Math.abs(arr[lo]-x) <= Math.abs(arr[hi]-x)) {
hi--;
} else {
lo++;
}
}
List<Integer> res = new ArrayList<>();
for(int i = lo; i <= hi; i++) {
res.add(arr[i]);
}
return res;
}
}
Given an array of numbers and a number ‘K’, we need to remove ‘K’ numbers from the array such that we are left with maximum distinct numbers.
这题和之前的套路类似:
时间复杂度分析:
我们需要把所有的number加到hashmap和minheap中,这一步会花费nlgn的时间。然后我们要把一些数字从minheap中取出来。最极端的情况是我们的数组里所有的数字都只出现了2次,这样的话最多需要把n/2个数取出来。取一个数的操作要消耗lgn的时间,那取n/2个数需要(n/2)(lgn)的时间。
所以最后的时间复杂度是: O(nglgn + n/2logn) = O(lgn) 空间复杂度:O(n)
public static int findMaximumDistinctElements(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums) {
map.put(num, map.getOrDefault(num, 0)+1);
}
PriorityQueue<Map.Entry<Integer, Integer>> minHeap = new PriorityQueue<>((a, b) -> a.getValue()-b.getValue());
int count = 0;
for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
if(entry.getValue() == 1) {
count++;
} else {
minHeap.offer(entry);
}
}
// following a greedy approach, try removing the least frequent numbers first from the min-heap
while(k > 0 && minHeap.size() > 0) {
Map.Entry<Integer, Integer> entry = minHeap.poll();
k -= entry.getValue()-1;
// to make an element distinct, we need to remove all of its occurrences except one
if(k >= 0) {
count++;
}
}
// if k > 0, this means we have to remove some distinct numbers
if(k > 0) {
count -= k;
}
return count;
}
Given an array, find the sum of all numbers between the K1’th and K2’th smallest elements of that array.
这题就很直白了,直接把所有的数字放到minheap里,把前k1个数字都poll出去,把接下来的k2-k1-1
个数相加,返回即可。
时间复杂度:O(nlgn)
public static int findSumOfElements(int[] nums, int k1, int k2) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for(int num : nums) {
minHeap.offer(num);
}
for(int i = 0; i < k1; i++) {
minHeap.poll();
}
int res = 0;
for(int i = 0; i < k2-k1-1; i++) {
res += minHeap.poll();
}
return res;
}
Given a string
s
, rearrange the characters ofs
so that any two adjacent characters are not the same. Return any possible rearrangement ofs
or return""
if not possible. Example 1: Input: s = "aab" Output: "aba" Example 2: Input: s = "aaab" Output: ""
这题和上一题类似,也是要用到贪心的思想。
时间复杂度:O(nlgn) 空间复杂度: O(n)
class Solution {
public String reorganizeString(String s) {
Map<Character, Integer> map = new HashMap<>();
for(char chr : s.toCharArray()) {
map.put(chr, map.getOrDefault(chr, 0)+1);
}
PriorityQueue<Map.Entry<Character, Integer>> maxHeap = new PriorityQueue<>((a, b) -> (b.getValue() - a.getValue()));
maxHeap.addAll(map.entrySet());
StringBuilder res = new StringBuilder();
Map.Entry<Character, Integer> prev = null;
while(!maxHeap.isEmpty()) {
Map.Entry<Character, Integer> curr = maxHeap.poll();
if(prev != null && prev.getValue() > 0) {
maxHeap.offer(prev);
}
res.append(curr.getKey());
curr.setValue(curr.getValue()-1);
prev = curr;
}
return res.length() == s.length() ? new String(res) : "";
}
}
Given a string and a number ‘K’, find if the string can be rearranged such that the same characters are at least ‘K’ distance apart from each other.
这题可以说是上一题的follow up,上一题是这一题的一种特殊情况k=2
罢了。
本质上思路还是一样的,上一题我们用prev这个变量来保存,但是这题因为k可以取到很大,所以我们可以用一个queue来保存之前已经遍历过的、但是还不能放回heap里的entry。
时间复杂度:O(nlgn) 空间复杂度: O(n)
public static String reorganizeString(String str, int k) {
if(k <= 1) {
return str;
}
Map<Character, Integer> map = new HashMap<>();
for(char chr : str.toCharArray()) {
map.put(chr, map.getOrDefault(chr, 0)+1);
}
PriorityQueue<Map.Entry<Character, Integer>> maxHeap = new PriorityQueue<>((a, b)->(b.getValue()-a.getValue()));
maxHeap.addAll(map.entrySet());
Queue<Map.Entry<Character, Integer>> queue = new LinkedList<>();
StringBuilder res = new StringBuilder();
while(!maxHeap.isEmpty()) {
Map.Entry<Character, Integer> curr = maxHeap.poll();
res.append(curr.getKey());
curr.setValue(curr.getValue()-1);
queue.offer(curr);
if(queue.size() == k) {
Map.Entry<Character, Integer> entry = queue.poll();
if(entry.getValue() > 0) {
maxHeap.offer(entry);
}
}
}
return res.length() == str.length() ? new String(res) : "";
}
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。 然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。 你需要计算完成所有任务所需要的 最短时间 。
这题和之前的题的思路也类似:
k+1
tasks。k+1
个tasks,我们要把CPU idle的时间加上。时间复杂度:O(nlgn) 空间复杂度: O(n)
代码如下:
class Solution {
public int leastInterval(char[] tasks, int k) {
int intervalCount = 0;
Map<Character, Integer> map = new HashMap<>();
for(char task : tasks) {
map.put(task, map.getOrDefault(task, 0)+1);
}
PriorityQueue<Map.Entry<Character, Integer>> maxHeap = new PriorityQueue<>((a, b) -> (b.getValue()-a.getValue()));
maxHeap.addAll(map.entrySet());
while(!maxHeap.isEmpty()) {
List<Map.Entry<Character, Integer>> waitlist = new ArrayList<>();
int n = k+1;
for(; n > 0 && !maxHeap.isEmpty(); n--) {
intervalCount++;
Map.Entry<Character, Integer> curr = maxHeap.poll();
if(curr.getValue() > 1) {
curr.setValue(curr.getValue()-1);
waitlist.add(curr);
}
}
maxHeap.addAll(waitlist);
if(!maxHeap.isEmpty()) {
intervalCount += n;
}
}
return intervalCount;
}
}
这题还有一个O(n)的解法,因为用上面的方法,本质上我们可以得到最后的implemented的task的顺序,但是事实上我们不需要得到这个顺序,我们只care我们需要多少个intervals。
那能不能用数学的角度来解决呢?
可以参考这个回答:
为什么最后要用tasks.length呢?
因为对于AAABBB 0来说, n there is 0, it means same task can put together, we just need to perform all the tasks. Therefore, our return result must be no less than the tasks' length, which is the reason to compare and choose a larger value.
class Solution {
public int leastInterval(char[] tasks, int n) {
int[] charMap = new int[26];
for(char task : tasks) {
charMap[task-'A']++;
}
Arrays.sort(charMap);
int numberOfTaskWithHighestFrequency = 0;
for(int i = 25; i >= 0; i--) {
if(charMap[i] == charMap[25]) {
numberOfTaskWithHighestFrequency++;
} else {
break;
}
}
return Math.max(tasks.length, (charMap[25]-1) * (n+1) + numberOfTaskWithHighestFrequency);
}
}
Design a class that simulates a Stack data structure, implementing the following two operations:
- push(int num): Pushes the number ‘num’ on the stack.
- pop(): Returns the most frequent number in the stack. If there is a tie, return the number which was pushed later.
这题的解题思路和top k frequent numbers很像。
我们可以用maxheap来保存这些numbers,我们以它们出现的frequency为优先级,如果frequency相同,我们就比较它们被push进来的时间先后顺序。
但是我们需要考虑两点:
所以,除了数字本身,我们还需要记录每个数字相应的sequence number和frequency。我们可以建一个object来保存这些信息,然后push进heap。
class Element {
int num;
int frequency;
int sequentialNum;
}
时间复杂度:push和pop都是O(lgn) 空间复杂度: O(n) for the heap
代码如下:
class FreqStack {
class Element {
int num;
int frequency;
int sequentialNum;
public Element(int num, int frequency, int sequentialNum) {
this.num = num;
this.frequency = frequency;
this.sequentialNum = sequentialNum;
}
}
int sequentialNum;
PriorityQueue<Element> maxHeap;
Map<Integer, Integer> map;
public FreqStack() {
maxHeap = new PriorityQueue<>((a, b) -> (a.frequency == b.frequency ? b.sequentialNum-a.sequentialNum : b.frequency-a.frequency));
map = new HashMap<>();
sequentialNum = 0;
}
public void push(int val) {
map.put(val, map.getOrDefault(val, 0)+1);
maxHeap.offer(new Element(val, map.get(val), sequentialNum++));
}
public int pop() {
int num = maxHeap.poll().num;
if(map.get(num) > 1) {
map.put(num, map.get(num)-1);
} else {
map.remove(num);
}
return num;
}
}
经常会有问题让我们求某个list里面的top/smallest/frequent K elements。比如经典的 215. Kth Largest Element in an Array 就是一道常见的面试题。
这一类问题,因为要维护一个size为k的set,通常情况下我们可以用heap来帮助我们解题。
在针对一些特定的题目,比如求top k appeared frequency的题目,我们可以用bucket sort来进一步优化。
这样说有一些抽象,下面就直接看例题吧。