Happy Years
Autumn Tournament (2007)
Submission name: happy.cpp
Problem summary
A four-digit year is happy if exactly one pair of its digits is equal and the other two digits are different from that pair and from each other. Among the supplied unhappy years, find the one with minimum absolute difference from a supplied happy year. The winning unhappy year is unique. Print 0 if either kind is absent.
Input
N followed by N four-digit positive years.
Output
The uniquely closest unhappy year, or 0.
Constraints
0 < N < 9000; years are between 1000 and 9999.
Worked example
Original statement sample.
Input
4 1254 1987 1271 2002
Output
1254
Solution analysis
- Count the occurrences of the ten possible digits. The happy frequency pattern is 2,1,1: one digit occurs twice and no digit occurs three or four times. In particular, two pairs do not meet the word “exactly”.
- Sort all supplied years, keeping their happy/unhappy labels. A closest pair with different labels can always be found at a boundary between two adjacent labels. Scan these boundaries and remember the unhappy endpoint of the smallest gap. Sorting costs far less than comparing every happy year with every unhappy year.
- In the sample, 1271 is happy, whereas 2002 contains two pairs and is unhappy. Sorted order is 1254, 1271, 1987, 2002. The first boundary gap is 17, and the next is 716, so the answer is 1254.
Why it works
If a minimum-gap opposite-kind pair had an intervening year, that intervening year has one of the two kinds and forms a no-larger opposite-kind gap with an endpoint. Repeating gives an adjacent opposite-kind pair. The scan considers all such pairs and records their unhappy endpoints.
Watch out. Do not search among years absent from the input. Use absolute numerical distance, not digit distance. Exactly one repeated pair excludes two pairs and triples.
Commented C++17 solution
An independently written complete program with standard headers.
#include<algorithm>
#include<array>
#include<iostream>
#include<vector>
using namespace std;
bool happy(int year){
array<int,10>frequency{};
for(int digit=0;digit<4;digit++){
frequency[year%10]++;
year/=10;
}
int pairs=0;
for(int count:frequency){
if(count>2){
return false;
}
if(count==2){
pairs++;
}
}
return pairs==1;
}
int main(){
int n;
cin>>n;
vector<int>years(n);
for(int&year:years){
cin>>year;
}
sort(years.begin(),years.end());
int bestGap=10000;
int answer=0;
for(int i=1;i<n;i++){
bool leftHappy=happy(years[i-1]);
bool rightHappy=happy(years[i]);
// Only boundaries between the two kinds can improve the answer.
if(leftHappy!=rightHappy&&years[i]-years[i-1]<bestGap){
bestGap=years[i]-years[i-1];
answer=leftHappy?years[i]:years[i-1];
}
}
cout<<answer<<'\n';
}