算法学习笔记

1、找出字符串中第一个只出现一次的字符
解题思路: 参考
对于char 的字符来说,总共有256种不同的字符,因此只需统计每一个字符在字符串中出现的次数就可以了,这样的话,使用一个哈希表就能解决这个问题。
定义哈希表的键值是字符,而值是该字符出现的次数。同时从头开始扫描字符串两次。第一次扫描字符串时,没扫描到一个字符,就在哈希表找到对应的项,把相应的值加1,这样,就能快速的找到第一个只出现一次的字符了。
第一次扫描时,在哈希表中更新第一个字符出现的次数的时间是O(1)。如果字符串长度为n,那么第一次扫描的时间复杂度是O(n)。第二次扫描时,同样在O(1)时间内能读出一个字符出现的次数,所以时间复杂度仍然是O(n)。这样算起来,总的时间复杂度是O(n)。同时,只需要一个包含256个字符的辅助数组就能解决,大小是1kb,由于这个数组的大小是一个常数,因此可以认为这种算法的空间复杂度为O(1)。

private static void solution() {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str = sc.nextLine();

            int[] table = new int[256];
            for (int i = 0, len = str.length(); i < len; i++) {
                table[str.charAt(i)]++;
            }
            boolean flag = true;
            for (int i = 0, len = str.length(); i < len; i++) {
                if (table[str.charAt(i)] == 1) {
                    System.out.println(str.charAt(i));
                    flag = false;
                    //找到第一个值出现一次的字符即可
                    break;
                }
            }
            if (flag) {
                System.out.println(-1);
            }
        }
    }



public int firstUniqChar(String s) {
        int[] arr = new int[256];
        //遍历一遍 把每个字符出现的次数记录下来
        for (int i=0, len=s.length(); i<len; i++) {
            arr[s.charAt(i)]++;
        }

        char c = 0;
        //第二遍 遍历 按字符串顺序查找 第一个只出现一次的字符 先被找到
        for (int i=0, len=s.length(); i<len; i++) {
            if (arr[s.charAt(i)] == 1) {
                c = s.charAt(i);
                break;
            }
        }
        return s.indexOf(c);
    }

//虽然慢,也是一种思路 一个从前面找,有个从后面找,如果唯一,返回的下标肯定相同
public int firstUniqChar(String s) {
        int l = -1, h = -1;

        for (int i=0,len=s.length(); i<len; i++) {
            l = s.indexOf(s.charAt(i));
            h = s.lastIndexOf(s.charAt(i));
            if (l == h) {
                return l;
            }
        }
        return -1;
    }

2、变量定义问题
错误示范

private static void solution() {
		//共享一个buffer,一直追加
        StringBuffer sb = new StringBuffer();
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int num = sc.nextInt();
            sc.nextLine();
            for (int i = 0; i < num; i++) {
                。。。
            }
            System.out.println(sb.toString());
        }
    }

正确定义

private static void solution() {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
        	//每次需要定义自己的buffer
            StringBuffer sb = new StringBuffer();
            int num = sc.nextInt();
            sc.nextLine();
            for (int i = 0; i < num; i++) {
                。。。
            }
            System.out.println(sb.toString());
        }
    }

3、多输入处理

public class Main {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String ss = sc.nextLine();
            String sl = sc.nextLine();
            System.out.println(solution(ss,sl));
        }
    }
   //只写单个判断的方法,循环放在主函数中处理
    private static boolean solution(String ss, String sl) {
        for (int i=0, len=ss.length(); i<len; i++) {
            if (sl.indexOf(ss.charAt(i)) == -1) {
             //可以看到  contains也是使用indexOf来实现的
         	 //if (sl.contains(ss.charAt(i))) {
			//public boolean contains(CharSequence s) {
			//return indexOf(s.toString()) > -1;
			//}
                return false;
            }
        }
        return true;
    }

    //循环放在Solution中,返回void,需要使用sout来输出,繁琐
    private static void solution2() {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String ss = sc.nextLine();
            String sl = sc.nextLine();
            boolean flag = false;
            for (int i = 0, len = ss.length(); i < len; i++) {
                if (sl.indexOf(ss.charAt(i)) == -1) {
                    System.out.println(false);
                    flag = true;
                    //若有一个字符没有找到  输出false 退出  否则会输出多个false
                    break;
                }
            }
            if (flag) {
            } else {
                System.out.println(true);
            }
        }
    }
}

4、参数解析 这个方法真他喵的巧

/**
 * 1.参数分隔符为空格
 * 2.对于用“”包含起来的参数,如果中间有空格,不能解析为多个参数。
 * 比如在命令行输入xcopy /s “C:\program files” “d:\”时,
 * 参数仍然是4个,第3个参数应该是字符串C:\program files,
 * 而不是C:\program,注意输出参数时,需要将“”去掉,引号不存在嵌套情况。
 * 3.参数不定长
 * 4.输入由用例保证,不会出现不符合要求的输入
 */
private static void solution(String str) {
        StringBuffer sb = new StringBuffer();
        int len = 0;
        int quotaNum = 0;
        //遍历这个串
        for (int i = 0; i < str.length(); i++){
            //是引号 记数 不加入
            if (str.charAt(i) == '\"') {
                quotaNum++;
                continue;
            }
            //非空格 只能是字符 加入(引号在前一步去掉了)
            if (str.charAt(i) != ' '){
                sb.append(str.charAt(i));
                //引号成对 或者没有引号 此时的空格都需要换行
                //没有引号 quotaNum==0 那么空格就会换行 并且空格不会加入buffer
                //引号成对了 换行
                //引号成对之后 空格换行
            } else if (quotaNum % 2 == 0) {
                sb.append('\n');
                len++;
                //是空格 需要加入
            }else {
                sb.append(' ');
            }
        }
        System.out.println(len+1);
        System.out.println(sb.toString());
    }

受到启发之后,又做了道类似的题目

 * 题目: 将一个字符中所有出现的数字前后加上符号“*”,其他字符保持不变
 * 输入: Jkdi234klowe90a3
 * 输出: Jkdi*234*klowe*90*a*3*
private static void solution(String str) {
        StringBuilder sb = new StringBuilder();
        int num = 0;
        for (int i=0, len=str.length(); i<len; i++) {
            char c = str.charAt(i);
            //如果 * 是偶数
            if (num % 2 == 0) {
                //不是数字 加入
                if (!(c >= 48 && c <= 57)) {
                    sb.append(c);
                    //是数字  加* 加入数字
                } else if (c >= 48 && c <= 57) {
                    sb.append('*');
                    sb.append(c);
                    num++;
                }
                //如果 * 是奇数
            } else {
                //遇到字母  先加入 *
                if (!(c >= 48 && c <= 57)) {
                    sb.append('*');
                    sb.append(c);
                    num++;
                    //遇到数字  直接加入
                } else {
                    sb.append(c);
                }
            }
        }
        //如果最后一个数字  需要加最后一个*
        if (num % 2 == 1) {
            sb.append('*');
        }
        System.out.print(sb.toString());
        System.out.println();
    }

5、素数判断

private static boolean isPrime(int num) {
        //假如n是合数,必然存在非1的两个约数p1和p2,其中p1<=sqrt(n),p2>=sqrt(n)。
        int sqrt = (int)Math.sqrt(num);
        for (int i=2; i<=sqrt; i++) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }

6、求解立方根

private static double getCubeRoot(double input) {
        double min = 0;
        double max = input;
        double mid = 0;

        while ((max - min) > 0.001) {
            mid = (max + min) / 2;
            if (mid * mid * mid > input) {
                max = mid;
            } else if (mid * mid * mid < input) {
                min = mid;
            } else {
                return mid;
            }
        }
        return max;
        //都可以
        //return min;
    }

7、大写正确检测

我们定义,在以下情况时,单词的大写用法是正确的:

全部字母都是大写,比如"USA"。
单词中所有字母都不是大写,比如"leetcode"。
如果单词不只含有一个字母,只有首字母大写, 比如 "Google"。

	String rex1 = "[a-z]";
    String rex2 = "[A-Z]";
    public boolean detectCapitalUse(String word) {

        String str = word.substring(1,word.length());
        //首字母小写
        if (String.valueOf(word.charAt(0)).matches(rex1)) {
           //剩余全部小写
            if (lowerCase(str)) {
                return true;
            } else {
                return false;
            }
        }
        //首字母大写
        if (String.valueOf(word.charAt(0)).matches(rex2)) {
            //剩余全部小写  或者  剩余全部大写
            if (lowerCase(str) || upperCase(str)) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

    private boolean lowerCase(String s) {
        for (int i=0; i<s.length(); i++) {
            if (!(String.valueOf(s.charAt(i)).matches(rex1))) {
                return false;
            }
        }
        return true;
    }

    private boolean upperCase(String s) {
        for (int i=0; i<s.length(); i++) {
            if (!(String.valueOf(s.charAt(i)).matches(rex2))) {
                return false;
            }
        }
        return true;
    }
他人的解法 
 * 判断大小写字母数量 大写 || 小写 等于字符串长度 true
 * 只有一个大写  是不是在首位即可

**8、验证回文串 **
要点1:边界
要点2:一次遍历,不使用额外空间

/**
 * 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
 * 输入: "A man, a plan, a canal: Panama"
 * 输出: true
 * 
 * 输入: "race a car"
 * 输出: false
 */
public boolean isPalindrome(String s) {
    String s1 = s.toLowerCase();
    String rex = "[a-zA-Z0-9]";

    int l=0, h=s1.length()-1;
    while (l < h) {
        //是字母或者数字
        //如果用if 只能跳过一个 若出现连续的非字母数字 无法辨别
        //如果不加l<h的话  会出现下标移除  例如两个空格"  ",l会一直++,直到溢出
        while (!String.valueOf(s1.charAt(l)).matches(rex) && l<h) {
            l++;
        }
        while (!String.valueOf(s1.charAt(h)).matches(rex) && l<h) {
            h--;
        }
        if (s1.charAt(l) != s1.charAt(h)) {
            return false;
        }
        l++;
        h--;
    }
    return true;
}

9、异或的使用

  • 异或 aabbc=c;
  • 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
  • 如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

力扣136,给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

public int singleNumber(int[] nums) {
        int result = nums[0];
        for (int i=1,len=nums.length; i<len; i++) {
            result ^= nums[i];
        }
        return result;
    }

力扣268,给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。

public int missingNumber(int[] nums) {

        //因为数字从0-n少一个,而数组下标是从0-n-1,只需要添加一个n,全部异或即可(添加0,异或i+1亦可)
        int res = nums.length;
        for (int i=0,len=nums.length; i<len; i++) {
            res ^= nums[i];
            res ^= i;
        }
        return res;
    }

10、公约数 && 公倍数
最大公约数
453%36=21;
36%21=15;
21%15=6;
15%6=3;
6%3=0;

最小公倍数
x * y / 最大 公约数

private static void solution(int x, int y) {
        int g = -1;
        while (true) {
            g = x % y;
            if (g == 0) {
                System.out.println(y);
                break;
            }
            x = y;
            y = g;
        }
    }

11、找出数组中重复的数

/**
 * 给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 
 * 其中有些元素出现两次而其他元素出现一次。
 */
public List<Integer> findDuplicates(int[] nums) {
    List<Integer> res = new ArrayList<>();
    for(int i = 0;i < nums.length;i++){
        //如果当前元素小于0,则表示之前出现过,加入结果集
        if(nums[Math.abs(nums[i])-1] < 0){
            res.add(Math.abs(nums[i]));
        }else{
            nums[Math.abs(nums[i])-1] *= -1;
        }
    }
    return res;
}

12、最长递增子序列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值