Pangkat 2 Terbesar Yang Kurang Dari Angka Yang Diberikan dengan Java

1. Ikhtisar

Dalam artikel ini, kita akan melihat cara mencari pangkat 2 terbesar yang lebih kecil dari bilangan yang diberikan.

Untuk contoh kita, kita akan mengambil contoh masukan 9. 20 adalah 1, masukan paling valid yang dapat kita temukan kekuatan 2 kurang dari masukan yang diberikan adalah 2. Karenanya kita hanya akan menganggap masukan yang lebih besar dari 1 sebagai valid .

2. Pendekatan Naif

Mari kita mulai dengan 20, yaitu 1, dan kita akan terus mengalikan angka tersebut dengan 2 sampai kita menemukan angka yang kurang dari 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 pahami kode untuk input sampel = 9.

Nilai awal firstPowerOf2 adalah 1 dan nextPowerOf2 adalah 2. Seperti yang dapat kita lihat, 2 <9 adalah true, dan kita masuk ke dalam while loop.

Untuk iterasi pertama, firstPowerOf2 adalah 2 dan nextPowerOf2 adalah 2 * 2 = 4. Sekali lagi 4 <9 jadi mari lanjutkan pengulangan while.

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

Untuk iterasi ketiga, firstPowerOf2 adalah 8 dan nextPowerOf2 adalah 8 * 2 = 16. Sedangkan kondisi while 16 <9 salah, sehingga break out dari while loop. 8 adalah pangkat 2 terbesar yang kurang dari 9.

Mari kita jalankan beberapa tes untuk memvalidasi kode kita:

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

Kompleksitas waktu solusi kami adalah O (log 2 (N)) . Dalam kasus kami, kami mengulangi log 2 (9) = 3 kali.

3. Menggunakan Math.log

Log basis 2 akan memberikan berapa kali kita dapat membagi angka dengan 2 secara rekursif dengan kata lain, log 2 dari sebuah angka memberikan pangkat 2 . Mari kita lihat beberapa contoh untuk memahami ini.

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

Oleh karena itu, jika kita menemukan bilangan yang habis dibagi 2, kita mengurangi 1 darinya sehingga kita menghindari skenario di mana bilangan tersebut adalah pangkat sempurna dari 2.

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

Mari kita masukkan dalam kode:

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 asumsi input sampel kami sebagai 9, nilai awal temp adalah 9.

9% 2 adalah 1, jadi variabel temp kita adalah 9.Di sini kita menggunakan pembagian modulo, yang akan memberikan sisa 9/2.

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

Sekarang, hasilnya adalah 23 yaitu 8.

Mari verifikasi kode kita:

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

Pada kenyataannya, Math.pow akan melakukan iterasi yang sama dengan yang kita lakukan pada pendekatan 1. Oleh karena itu, kita dapat mengatakan bahwa untuk solusi ini juga, kompleksitas waktunya adalah O (Log 2 (N)) .

4. Teknik Bitwise

Untuk pendekatan ini, kami akan menggunakan teknik pergeseran bitwise. Pertama, mari kita lihat representasi biner untuk pangkat 2 mengingat kita memiliki 4 bit untuk mewakili bilangan tersebut

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

Melihat lebih dekat, kita dapat mengamati bahwa kita dapat menghitung pangkat 2 dengan menggeser byte ke kiri untuk 1 . yaitu. 22 adalah byte shift kiri untuk 1 kali 2 tempat dan seterusnya.

Mari membuat kode menggunakan teknik bitshift:

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; }

Pada kode di atas, kami menggunakan tipe data long kami, yang menggunakan 8 byte atau 64 bit. Jadi kita akan menghitung pangkat 2 hingga 264. Kita menggunakan operator bit shift << untuk mencari pangkat 2. Untuk input sampel kita 9, setelah iterasi ke-4, nilai powerOf2 = 16 dan result = 8 di mana kita keluar dari loop sebagai 16> 9 input .

Mari kita periksa apakah kode kita berfungsi seperti yang diharapkan:

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

The terburuk kompleksitas waktu untuk pendekatan ini adalah lagi O (log 2 (N)) , mirip dengan apa yang kita lihat untuk pendekatan pertama. Namun, pendekatan ini lebih baik karena operasi bit shift lebih efisien dibandingkan dengan perkalian .

5. Bitwise 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 berbeda untuk menemukan pangkat terbesar dari 2 yang lebih kecil dari bilangan yang diberikan. Kami juga memperhatikan bagaimana operasi bitwise dapat menyederhanakan penghitungan dalam beberapa kasus.

Kode sumber lengkap dengan pengujian unit untuk artikel ini dapat ditemukan di GitHub.