当前位置: 首页 > 知识库问答 >
问题:

求大于给定数且与给定整数具有相同二进制权重的最小ve整数的算法

谢英耀
2023-03-14

正整数的二进制权重是其二进制表示中1的个数。例如,十进制数1的二进制权重为1,十进制数7(二进制为111)的二进制权重为3。

给定一个正整数N,找出与N具有相同二进制权重的大于N的最小整数。

public static int compute(int number)   {
    int  count = 0, nextNumber;
    char[] arr =  Integer.toBinaryString(number).toCharArray();
    for(int i =0 ; i < arr.length ;++i) {
        if(arr[i] == '1')
            ++count;
    }
    nextNumber = findNextNumber(number,count);
    return nextNumber;
}
public static int findNextNumber(int number, int weight) {
    char[] arr;
    boolean flag = true;
    int count;
    while (flag) {
        // increment number and convert it into char array
        arr = Integer.toBinaryString(++number).toCharArray();
        count = 0;
        for(int i =0 ; i < arr.length; ++i) {
            if(arr[i] == '1')
                ++count;
        }
        if(count == weight) {
            flag = false;
        }
    }

    return number;
}

我的解决方案运行良好,但它的复杂性似乎是O(NlogN)。这可以通过其他方法在O(N)或O(logn)中实现吗?

共有3个答案

许昆
2023-03-14

找到了一种在O(logn)复杂度上实现相同的方法。

主要步骤:-

  1. 将数字转换为二进制字符数组。(非常简单)
  2. 根据模式对二进制数组进行分类。(在评论中解释)
  3. 根据类别调整二进制数组的0和1
  4. 将二进制字符数组转换回数字

代码:-

public static int compute(int number)   {
    int bitPatternCategory , result;
    char[] charArr = Integer.toBinaryString(number).toCharArray();
    bitPatternCategory = determineNumberType(charArr);
    result = findNextDesired(bitPatternCategory, charArr);
    return result;
}
public static int findNextDesired(int bitPatternCategory, char[] arr) {
    int number;
    //System.out.print("bitPatternCategory\t"+bitPatternCategory+"\n");
    char[] temp = new char[arr.length + 1];
    if (bitPatternCategory == 0) {
        temp = getNextForCat0(arr, temp);
    } else if (bitPatternCategory == 1) {
        temp = getNextForCat1(arr, temp);
    } else {
        temp = getNextForCat2(arr);
    }
    number = Integer.parseInt(String.valueOf(temp),2);
    return number;
}

private static char[] getNextForCat2(char[] arr) {
    // for all cases except cat 0 and 1, for example 110011000,  1001, 1101010
    //  Find first occurrence of 0 after 1 starting from RHS, exchange these bits and then move
    // all remaining 1's(on RHS to the exchanged bits) to RHS of the array
    int j =0,counterForOnes = 0;
    boolean flag = false;
    for (int i = arr.length - 1; i >= 0; --i) {
        if ((arr[i] == '1') && (flag == false)) {
            flag = true;
        } else if ((arr[i] == '0') && (flag == true)) {
            char tempChar = arr[i];
            arr[i] = arr[i + 1];
            arr[i + 1] = tempChar;
            j = i+2;
            break;
        }
    }
    while((j < arr.length) && (arr[j]!='0'))    {
        arr[j] = '0';
        ++counterForOnes;
        ++j;
    }
    while(counterForOnes > 0) {
        arr[arr.length-counterForOnes]= '1';
        counterForOnes--;
    }
    return arr;
}

private static char[] getNextForCat1(char[] arr, char[] temp) {
    // for cases when all ones are on LHS for eg 11100, then add a new bit with value 1 and
    //  shift remaining 1's start from 2nd 1 towards RHS, so 1111 become 10111
    int j = 1,counterForOnes= 0;
    while((j < arr.length) && (arr[j]!='0'))    {
        arr[j] = '0';
        ++counterForOnes;
        ++j;
    }
    for (int i = 0; i < arr.length; ++i) {
        temp[i] = arr[i];
    }
    temp[temp.length-1] = '0';
    while(counterForOnes > 0) {
        temp[temp.length-counterForOnes]= '1';
        counterForOnes--;
    }
    arr = temp;
    return arr;
}

private static char[] getNextForCat0(char[] arr, char[] temp) {
    // for cases when all bits are ones only, then add a new bit with value 1 and
    //  shift remaining 1's start from 2nd 1 towards RHS, so 1111 become 10111
    for (int i = 0; i < arr.length; ++i) {
        temp[i] = arr[i];
    }
    for (int i = temp.length - 1; i >= 1; --i)
        temp[i] = temp[i - 1];
    temp[1] = '0';
    arr = temp;
    return arr;
}

public static int determineNumberType(char[] arr)   {
    int stateMachine = 0;   //Category 0 for all ones for eg 111, 1111
                            //Category 1 for ones and zeroes  11100, 110000
                            //Category 2 for mix ones or we can say remaining combinations 1011, 11101
    // Assuming MSB will always be 1
    char temp = arr[0];
    for(int i = 0 ; i < arr.length ; ++i)   {
        if((temp == arr[i]) && (stateMachine == 0)) {
            stateMachine = 0;
        } else if(((temp != arr[i])) && (stateMachine == 0))    {
            stateMachine = 1;
            temp = arr[i];
        }else if(((temp == arr[i])) && (stateMachine == 1)) {
            stateMachine = 1;
        }else if(((temp != arr[i])) && (stateMachine == 1)) {
            stateMachine = 2;
            //temp = arr[i];
            break;
        }
    }   
    return stateMachine;
}
乐正烨熠
2023-03-14

可以对下一个字典排列使用算法。整型数组的Java实现。只需调整它以使用位而不是数组项:

boolean nextPermutation(int[] array) {
    // Find longest non-increasing suffix
    int i = array.length - 1;
    while (i > 0 && array[i - 1] >= array[i])
        i--;
    // Now i is the head index of the suffix

    // Are we at the last permutation already?
    if (i <= 0)
        return false;

    // Let array[i - 1] be the pivot
    // Find rightmost element that exceeds the pivot
    int j = array.length - 1;
    while (array[j] <= array[i - 1])
        j--;
    // Now the value array[j] will become the new pivot
    // Assertion: j >= i

    // Swap the pivot with j
    int temp = array[i - 1];
    array[i - 1] = array[j];
    array[j] = temp;

    // Reverse the suffix
    j = array.length - 1;
    while (i < j) {
        temp = array[i];
        array[i] = array[j];
        array[j] = temp;
        i++;
        j--;
    }

    // Successfully computed the next permutation
    return true;
}
陶博涉
2023-03-14

这种操作有时被称为“snoob”。以下是《黑客的快乐书》中的一系列方法。也许最好使用整数。可能编译为硬件指令(未测试)的跟踪零数:

int snoob1(int x) {
   int smallest, ripple, ones;  // x = xxx0 1111 0000
   smallest = x & -x;           //     0000 0001 0000
   ripple = x + smallest;       //     xxx1 0000 0000
   ones = x ^ ripple;           //     0001 1111 0000
   ones = ones >>> (2 + Integer.numberOfTrailingZeros(x)); //     0000 0000 0111
   return ripple | ones;        //     xxx1 0000 0111
}

(由于Java中的移位计数是模32,所以“2”部分可能存在溢出问题)

 类似资料:
  • 给出不同整数的列表 我的想法:< br >一种简单的方法是一个接一个地选择一个元素,看看它形成的完美子集的大小,然后我们可以简单地返回最大值。这将是计算密集型的。< br >有什么好的解决方案吗

  • 我的问题很简单,但我不知道如何解决我想要的。我必须找到小于给定数字的最大数素数,如果不存在则打印消息。 代码是有效的,如果数字是10,它会打印7,但我想做2个新的修改,我找不到解决方案。例如,如果给定的数字是1,我的程序应该如何修改以打印消息?我试着写一个if-else,但是如果我用if修改了while,这将不会有帮助。第二件事,如果给定的数是素数,代码仍然会找到比给定数少的数。如果我给数字7,输

  • 我想找到一组素数的最小集合,它可以和一个给定的值,例如9=7+2(而不是3+3+3)。 我已经使用eratosthens筛生成了一个数组素数 我正在按降序遍历数组,以获得数组中小于或等于给定数的最大素数。如果数字是奇数,这很有效。但对于偶数(例如122=113+7+2,但122=109+13)则失败。

  • 我试着写一个代码,它接受一个介于1和1_000_000之间的整数,并返回一个比相同数字的整数大的最小整数,如果它不存在,则打印0。 举个例子 输入:156 输出165 输入330 输出0 输入27711 输出71127 我的问题是,下面的代码没有为其他输入返回正确的输出。 例如,在输入4231中,输出应该是4312。 我很难找到为每个输入返回正确输出的最佳算法。 TNX提前 }

  • 给定一个无序整数列表,以这种方式打印两个总计为的整数(int 1小于或等于int 2,它们之间用空格隔开)。假设整数列表中总是有的解。int1和int2必须是正整数。 如果有多个解决方案,请打印差异最小的整数对。 例子: 这是我的代码,但是根据我们的编译器(这是我们班的一个练习),我对隐藏的测试用例有错误的输出。 更新:代码工作!

  • 给定一个数组形式的未排序(多)整数集,求其和大于或等于常量整数x的最小基数子集。 我们的集合是{4 5 8 10 10},x=15,所以最小基数子集和 这个问题与以下问题相关但不同:给定一个n个整数的列表,找到大于X的最小子集和在前面的问题中,作者要求得到一个和最接近X的子集,这里我们想要任何子集