The first method to solve this problem is using O(k) time w/ O(k) memory where k indicates length of input in binary form.
//java code:
public class program {
public static int longestSequence(int n) {
if (n == -1) return 32;
ArrayList<Integer> sequences = getSeq(n);
for(int i = 0; i<sequences.size(); ++i ){
System.out.print(i + " => ");
System.out.println(sequences.get(i));
}
return findSeq(sequences);
}
/* Return a list of the sizes of the sequences. The sequence starts
* off with the number of 0s (which might be 0) and then alternates
* with the counts of each value.*/
public static ArrayList<Integer> getSeq(int n){
ArrayList<Integer> seq = new ArrayList<Integer>();
int searchFor = 0, cnt = 0;
for(int i = 0; i<32; ++i){
if ((n & 1) != searchFor){
seq.add(cnt);
searchFor = n & 1;// try to find another bit(0 or 1);
cnt = 0;
}
++cnt;
n >>= 1;
}
seq.add(cnt);
return seq;
}
public static int findSeq(ArrayList<Integer> seq){
int maxSeq = 1;
for(int i = 0; i<seq.size(); i += 2){
int zeroSeq = seq.get(i);
int leftOneSeq = ((i + 1) < seq.size()) ? seq.get( i+1 ) : 0;
int rightOneSeq = ((i-1) >= 0) ? seq.get(i-1) : 0;
if(zeroSeq > 1) maxSeq = Math.max(maxSeq, (Math.max(leftOneSeq, rightOneSeq) + 1));// there are at least two 0s together, but we can only change one!
else if(zeroSeq == 1) maxSeq = Math.max(leftOneSeq + rightOneSeq + 1, maxSeq);
else maxSeq = Math.max(Math.max(leftOneSeq, rightOneSeq), maxSeq);
}
return maxSeq;
}
public static void main(String[] args) {
int original_number = 1775;
int new_number = longestSequence(original_number); System.out.println(Integer.toBinaryString(original_number));
System.out.println(new_number);
}
}
c++ code:
vector<int> getSeq( int n){
int searchFor = 0, cnt = 0;
vector<int> seq;
for (int i = 0; i<32; ++i) {
if ((n&1)!= searchFor){
seq.push_back(cnt);
searchFor = n & 1;
cnt = 0;
}
++cnt;
n >>= 1;
}
return seq;
}
int findSeq(vector<int>& seq){
int maxSeq = 1;
for (int i = 0; i<seq.size(); ++i) {
int zeroSeq = seq[i], left = (i+1) < seq.size() ? seq[i+1] : 0, right = (i-1)>=0 ? seq[i-1] : 0;
if (zeroSeq > 1) maxSeq = max(maxSeq, max(left, right)+1);
else if(zeroSeq == 1) maxSeq = max(maxSeq, left + right + 1);
else maxSeq = max(maxSeq, max(left, right));
}
return maxSeq;
}
int findLongestSeq(int n){
if (n==-1) return 32;
vector<int> seq = getSeq(n);
return findSeq(seq);
}
Optimize: only keep leftOneSeq, zeroSeq, rightOneSeq each time by using * int[] seq = { 0, 0, 0 } * . The memory reduces to O(1);
public class program {
static int findMax(int[] seq){
if(seq[1] == 1) return seq[0] + seq[1] + 1;
else if(seq[1] == 0) return Math.max(seq[0], seq[2]);
else return Math.max(seq[0], seq[2]) + 1;
}
static void shift(int[] seq){
seq[2] = seq[1];
seq[1] = seq[0];
seq[0] = 0;
}
public static int longestSequence(int n) {
if (n == -1) return Integer.BYTES * 8;
int[] seq = {0, 0, 0};
int maxSeq = 1, searchFor = 0;
for(int i =0; i<32; ++i){
if((n & 1) != searchFor){
if(searchFor == 1) maxSeq = Math.max(maxSeq, findMax(seq));//we already find two 1s seq;
searchFor = n & 1;
shift(seq);
}
seq[0]++;// if we are searching what we want, just keep updating seq[0].
n >>= 1;//if we want to shif sign as well, we should use n >>>= 1;
}
return maxSeq;
}
public static void main(String[] args) {
int original_number = 2222;
int new_number = longestSequence(original_number);
System.out.println(Integer.toBinaryString(original_number));
System.out.println(new_number);
}
}