對於每個數字,記錄他的值以及他所在的行數,然後把所有數字從小到大排序,建立左指針和右指針,只要左右指針之間包含的數沒有遍佈所有行(用cnt計數,vis數組記錄每行出現的次數),就將右指針右移。遍佈所有行之後,左指針右移知道左指針對應的數字所在的行只出現了一次(如果再右移就不滿足遍佈所有行的要求了),刷新答案。
#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
#include <cstdlib>
#include <math.h>
#include <cstring>
#include <iomanip>
using namespace std;
#define ll long long
#define N 1000100
#define INF 0x3f3f3f3f
struct Node
{
int data;
int num;
Node(int a = 0,int b = 0){
data = a,num = b;
}
}l[N];
bool cmp(Node a,Node b){
return a.data < b.data;
}
int vis[N] = {0};
int n,m;
int main(){
int i,j;
int cnt = 0;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
scanf("%d",&l[(i-1)*m+j].data);
l[(i-1)*m+j].num = i;
}
}
if(n == 1){
printf("0\n");
return 0;
}
sort(l+1,l+1+n*m,cmp);
int left = 1,right = 1;
cnt = 1;
vis[l[left].num]++;
int ans = INF;
while (right < n*m)
{
right++;
if(vis[l[right].num] == 0){
cnt++;
if(cnt == n){
while (vis[l[left].num] > 1)
{
vis[l[left].num]--;
left++;
}
ans = min(ans,l[right].data - l[left].data);
vis[l[left].num]--;
left++;
cnt--;
}
}
vis[l[right].num]++;
}
printf("%d\n",ans);
return 0;
}
使用尺取法的核心在於,對於我們目前所選的區間,我們能夠明顯的判斷左右指針接下來應該向哪裏移動。