Kuasa Terbesar dari 2 Yang Kurang daripada Nombor yang Diberikan dengan Java

1. Gambaran keseluruhan

Dalam artikel ini, kita akan melihat bagaimana mencari kekuatan terbesar 2 yang kurang daripada nombor yang diberikan.

Sebagai contoh, kami akan mengambil input input 9. 20 adalah 1, input paling tidak sah yang mana kami dapati kekuatan 2 lebih sedikit daripada input yang diberikan adalah 2. Oleh itu, kami hanya akan menganggap input lebih besar daripada 1 sebagai sah .

2. Pendekatan Naif

Mari kita mulakan dengan 20, yang merupakan 1, dan kita akan terus mengalikan nombor dengan 2 sehingga kita mendapat nombor yang kurang daripada input :

public long findLargestPowerOf2LessThanTheGivenNumber(long input) { Assert.isTrue(input > 1, "Invalid input"); long firstPowerOf2 = 1; long nextPowerOf2 = 2; while (nextPowerOf2 < input) { firstPowerOf2 = nextPowerOf2; nextPowerOf2 = nextPowerOf2 * 2; } return firstPowerOf2; }

Mari kita fahami kod untuk input sampel = 9.

Nilai awal untuk firstPowerOf2 adalah 1 dan nextPowerOf2 adalah 2. Seperti yang kita lihat, 2 <9 adalah benar, dan kita masuk ke dalam loop sementara.

Untuk lelaran pertama, firstPowerOf2 adalah 2 dan nextPowerOf2 adalah 2 * 2 = 4. Sekali lagi 4 <9 jadi mari kita teruskan loop sementara.

Untuk lelaran kedua, firstPowerOf2 adalah 4 dan nextPowerOf2 adalah 4 * 2 = 8. Sekarang 8 <9, mari kita teruskan.

Untuk lelaran ketiga, firstPowerOf2 adalah 8 dan nextPowerOf2 adalah 8 * 2 = 16. Keadaan sementara 16 <9 adalah salah, jadi ia keluar dari loop sementara. 8 adalah kuasa terbesar 2 iaitu kurang dari 9.

Mari jalankan beberapa ujian untuk mengesahkan kod kami:

assertEquals(8, findPowerOf2LessThanTheGivenNumber(9)); assertEquals(16, findPowerOf2LessThanTheGivenNumber(32)); 

Kerumitan masa penyelesaian kami adalah O (log 2 (N)) . Dalam kes kami, kami mengulangi log 2 (9) = 3 kali.

3. Menggunakan Math.log

Log log 2 akan memberikan berapa kali kita dapat membahagi nombor dengan 2 secara berulang dengan kata lain, log 2 nombor memberikan kekuatan 2 . Mari lihat beberapa contoh untuk memahami perkara ini.

log 2 (8) = 3 dan log 2 (16) = 4. Secara umum, kita dapat melihat bahawa y = log 2 x di mana x = 2y.

Oleh itu, jika kita menjumpai nombor yang dapat dibahagi dengan 2, kita tolak 1 darinya sehingga kita mengelakkan senario di mana nombor itu adalah kekuatan 2 yang sempurna.

Math.log adalah log 10 . Untuk mengira log 2 (x), kita dapat menggunakan formula log 2 (x) = log 10 (x) / log 10 (2)

Mari masukkannya dalam kod:

public long findLargestPowerOf2LessThanTheGivenNumberUsingLogBase2(long input) { Assert.isTrue(input > 1, "Invalid input"); long temp = input; if (input % 2 == 0) { temp = input - 1; } long power = (long) (Math.log(temp) / Math.log(2)); long result = (long) Math.pow(2, power); return result; }

Dengan andaian input sampel kami sebagai 9, nilai awal temp adalah 9.

9% 2 adalah 1, jadi pemboleh ubah temp kami adalah 9.Di sini kita menggunakan pembahagian modulo, yang akan memberikan baki 9/2.

Untuk mencari log 2 (9), kita melakukan log 10 (9) / log 10 (2) = 0.95424 / 0.30103 ~ = 3.

Sekarang, hasilnya adalah 23 iaitu 8.

Mari sahkan kod kami:

assertEquals(8, findLargestPowerOf2LessThanTheGivenNumberUsingLogBase2(9)); assertEquals(16, findLargestPowerOf2LessThanTheGivenNumberUsingLogBase2(32));

Pada hakikatnya, Math.pow akan melakukan iterasi yang sama seperti yang kita lakukan dalam pendekatan 1. Oleh itu kita dapat mengatakan bahawa untuk penyelesaian ini juga, kerumitan masa adalah O (Log 2 (N)) .

4. Teknik Bitwise

Untuk pendekatan ini, kami akan menggunakan teknik shift bitwise. Pertama, mari kita perhatikan perwakilan binari untuk kekuatan 2 memandangkan kita mempunyai 4 bit untuk mewakili nombor

20 1 0001
21 2 0010
22 4 0100
23 8 1000

Melihat dengan teliti, kita dapat melihat bahawa kita dapat menghitung kekuatan 2 dengan kiri menggeser bait untuk 1 . iaitu. 22 adalah byte shift kiri untuk 1 oleh 2 tempat dan seterusnya.

Mari kod menggunakan teknik pertukaran bit:

public long findLargestPowerOf2LessThanTheGivenNumberUsingBitShiftApproach(long input) { Assert.isTrue(input > 1, "Invalid input"); long result = 1; long powerOf2; for (long i = 0; i < Long.BYTES * 8; i++) { powerOf2 = 1 <= input) { break; } result = powerOf2; } return result; }

Dalam kod di atas, kita menggunakan selagi jenis data kita, yang menggunakan 8 bait atau 64 bit. Oleh itu, kita akan mengira kekuatan 2 hingga 264. Kami menggunakan operator peralihan bit << untuk mencari kekuatan 2. Untuk input sampel kami 9, selepas lelaran ke-4, nilai powerOf2 = 16 dan hasil = 8 di mana kita keluar dari gelung sebagai 16> 9 input .

Mari periksa sama ada kod kami berfungsi seperti yang diharapkan:

assertEquals(8, findLargestPowerOf2LessThanTheGivenNumberUsingBitShiftApproach(9)); assertEquals(16, findLargestPowerOf2LessThanTheGivenNumberUsingBitShiftApproach(32));

Yang masa kerumitan kes terburuk untuk pendekatan ini sekali lagi O (log 2 (N)) , sama dengan apa yang kita lihat pendekatan yang pertama. Walau bagaimanapun, pendekatan ini lebih baik kerana operasi pergeseran bit lebih efisien berbanding pendaraban .

5. Sedikit demi sedikit DAN

For our next approach, we'll be using this formula 2n AND 2n -1 = 0.

Let's look at some examples to understand how it works.

The binary representation of 4 is 0100, and 3 is 0011.

Let's do a bitwise AND operation on these two numbers. 0100 AND 0011 is 0000. We can say the same for any power of 2 and a number less than it. Let's take 16 (24) and 15 which is represented as 1000, 0111 respectively. Again, we see that the bitwise AND on these two results in 0. We can also say that the AND operation on any other number apart from these 2 won't result in a 0.

Let's see the code for solving this problem using bitwise AND:

public long findLargestPowerOf2LessThanTheGivenNumberUsingBitwiseAnd(long input) { Assert.isTrue(input > 1, "Invalid input"); long result = 1; for (long i = input - 1; i > 1; i--) { if ((i & (i - 1)) == 0) { result = i; break; } } return result; }

In the above code, we loop over numbers less than our input. Whenever we find the bitwise AND of a number and number-1 is zero, we break out of the loop, as we know that number will be a power of 2. In this case for our sample input 9, we break out of the loop when i = 8 and i – 1 = 7.

Now, let's verify a couple of scenarios:

assertEquals(8, findLargestPowerOf2LessThanTheGivenNumberUsingBitwiseAnd(9)); assertEquals(16, findLargestPowerOf2LessThanTheGivenNumberUsingBitwiseAnd(32));

The worst-case time complexity for this approach is O(N/2) when the input is an exact power 2. As we can see, this is not the most efficient solution, but it is good to know this technique as it could come handy when tackling similar problems.

6. Conclusion

Kami telah melihat pendekatan yang berbeza untuk mencari kekuatan terbesar 2 yang kurang daripada bilangan yang diberikan. Kami juga menyedari bagaimana operasi bitwise dapat memudahkan pengiraan dalam beberapa kes.

Kod sumber lengkap dengan ujian unit untuk artikel ini boleh didapati di GitHub.