蓝桥杯算法学习(1)

00 学习建议

好程序员是练出来的,编程是手上的活儿,要重视实践

知识盲区需要自己见多识广去补充

参考权威《程序员面试金典》《挑战程序设计竞赛》《程序员代码面试实践》《剑指offer》《编程之美》《算法导论》

关于学习:阅读(听课)–》笔记 --》实践 --》反思 --》提问 (所有步骤需要重复)

在这里插入图片描述

01 位运算的奇巧淫技

1 相关基础

在处理整形数值时,可以直接对组成整形数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位

&(与)、|(或)、^(异或)、~(非/取反)

<<和>> 运算符将二进制位进行左移或者右移操作

运算符>>>将用0填充高位;运算符>>用符号位填充高位,没有运算符<<<

对于int型,1<<35与1<<3是相同的,而左边的操作数是long型时需对右侧操作数模64

与:都为1结果为1,或:有一个为1结果为1,异或:两者不同时结果为1

在这里插入图片描述

2 用处

判断奇偶数

获取二进制位是1还是0(两种解决方案)

交换两个整数变量的值

不用判断语句,求整数的绝对值

​ 异或,可以理解为不进位加法:1+1=0,0+0=0,1+0=1

​ 性质

​ 1、交换律可任意交换运算因子的位置,结果不变

​ 2、结合律(即(ab)c==a(bc))

​ 3、对于任何数x,都有xx=0,x0=x,同自己求异或为0,同0求异或为自己

​ 4、自反性ABB=A^0=A,连续和同一个因子做异或运算,最终结果为自己

3 相关题解

题1:找出唯一成对的数

1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?

package org.lanqiao.algo.elementary._01xor;

import org.lanqiao.algo.util.Util;

import java.util.Random;

public class _01唯一成对的数 {
  public static void main(String[] args) {
    int N = 1001;
    int[] arr = new int[N];
    for (int i = 0; i < arr.length - 1; i++) {
      arr[i] = i + 1;
    }
    //最后一个数,是随机数
    arr[arr.length - 1] = new Random().nextInt(N - 1) + 1;
    //随机下标
    int index = new Random().nextInt(N);
    Util.swap(arr, index, arr.length - 1);
    Util.print(arr);
    int x1 = 0;
    for (int i = 1; i <= N - 1; i++) {
      x1 = (x1 ^ i);
    }
    for (int i = 0; i < N; i++) {
      x1 = x1 ^ arr[i];
    }
    System.out.println(x1);

    System.out.println("==========");
    int[] helper = new int[N];
    for (int i = 0; i < N; i++) {
      helper[arr[i]]++;
    }
    for (int i = 0; i < N; i++) {
      if (helper[i] == 2) {
        System.out.println(i);
        break;
      }
    }
  }
}
题2:找出落单的那个数

一个数组里除了某一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。

题3:二进制中1的个数

请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。

例:9的二进制表示为1001,有2位是1

package org.lanqiao.algo.elementary._01xor;

import java.util.Scanner;

public class _03_1的个数 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int N = sc.nextInt();
    System.out.println(Integer.toString(N, 2));

    int count = 0;
    //比对每一位
    for (int i = 0; i < 32; i++) {
      if ((N & (1 << i)) == (1 << i)) {
        count++;
      }
    }
    System.out.println(count);

    count = 0;
    for (int i = 0; i < 32; i++) {
      if (((N >>> i) & 1) == 1)
        count++;
    }
    System.out.println(count);

    count = 0;
    while (N != 0) {
      N = ((N - 1) & N);
      count++;
    }
    System.out.println(count);
  }
}
题4:是不是2的整数次方

用一条语句判断一个整数是不是2的整数次方。(利用位运算操作判断)

题5:将整数的奇偶位互换

在这里插入图片描述

package org.lanqiao.algo.elementary._01xor;

import org.assertj.core.api.Assertions;

public class _05_交换奇偶位 {

  public static void main(String[] args) {
    int a = 0b01000000_00000000_00000000_00000000;
    System.out.println(a);
    int b = m(a);
    System.out.println(b);
    Assertions.assertThat(b).isEqualTo(0b10000000_00000000_00000000_00000000);
  }

  private static int m(int i) {
    int ou = i & 0xaaaaaaaa;//和1010 1010 1010 。。。。做与运算取出偶数位
    int ji = i & 0x55555555;//和0101 0101 0101.。。。。做与运算取出奇数位
    return (ou >> 1) ^ (ji << 1); // 连起来
  }
}
题6:0~1间浮点实数的二进制表示

给定一个介于0和1之间的实数,(如0.625),类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25.0.125…) 。

如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”

package org.lanqiao.algo.elementary._01xor;

public class _06_二进制小数 {
  public static void main(String[] args) {
    double num = 0.625;
    StringBuilder sb = new StringBuilder("0.");
    while (num > 0) {
      //乘2:挪整
      double r = num * 2;
      //判断整数部分
      if (r >= 1) {
        sb.append("1");
        //消掉整数部分
        num = r - 1;
      } else {
        sb.append("0");
        num = r;
      }

      if (sb.length() > 34) {
        System.out.println("ERROR");
        return;
      }

    }
    System.out.println(sb.toString());
  }
}
题7:出现k次与出现1次

数组中只有一个数出现了1次,其他的数都出现了k次,请输出只出现了1次的数。

note:2个相同的二进制数做不进位加法,结果为0

10个相同的10进制数做不进位加法,结果为0

K个相同的K进制数做不进位加法,结果为0

package org.lanqiao.algo.elementary._01xor;

public class _07_出现K次 {
  public static void main(String[] args) {
    int[] arr = {2, 2, 2, 9, 7, 7, 7, 3, 3, 3, 6, 6, 6, 0, 0, 0};
    int len = arr.length;
    char[][] kRadix = new char[len][];
    int k = 3;

    int maxLen = 0;
    //转成k进制字符数组
    //对于每个数字
    for (int i = 0; i < len; i++) {
      //求每个数字的三进制字符串并翻转,然后转为字符数组
      kRadix[i] = new StringBuilder(Integer.toString(arr[i], k)).reverse().toString().toCharArray();
      if (kRadix[i].length > maxLen)
        maxLen = kRadix[i].length;
    }
    //不进位加法
    int[] resArr = new int[maxLen];
    for (int i = 0; i < len; i++) {
      //  不进位加法
      for (int j = 0; j < maxLen; j++) {
        if (j >= kRadix[i].length)
          resArr[j] += 0;
        else
          resArr[j] += (kRadix[i][j] - '0');
      }
    }

    int res = 0;
    for (int i = 0; i < maxLen; i++) {
      res += (resArr[i] % k) * (int) (Math.pow(k, i));// 8%3=2,
    }
    System.out.println(res);
  }
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值