数组3+字符串4+位运算1

1. 数组中重复的数字

题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

import java.util.HashSet;
public class Solution {

    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null||length<=0) return false;
        HashSet<Integer> set =new HashSet<>();
        for(int i=0;i<length;i++){
            if(set.contains(numbers[i])){
                duplication[0]=numbers[i];
                return true;
            }
            set.add(numbers[i]);
        }
        return false;
    
    }
}
public class Solution {

    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null||length<=0) return false;
        boolean[] judge =new boolean[length];
        for(int i=0;i<length;i++){
            if(judge[numbers[i]]==true){
                duplication[0]=numbers[i];
                return true;
            }
            else judge[numbers[i]]=true;
        }
        return false;
    
    }
}
import java.util.Arrays;
public class Solution {


    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false



    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null||length<=0) return false;
        int flag=0;
        Arrays.sort(numbers);
        for(int i=0;i<length-1;i++){
            if(numbers[i]==numbers[i+1]){
                duplication[0]=numbers[i];
                flag=1;
                break;
            }
        }
        return flag==1?true:false;
    }
}

2. 构建乘积数组

给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        if(A.length==0) return new int[0];
        int length =A.length;
        int[] B=new int[length];
        B[0]=1;
        计算下三角连乘
        for(int i=1;i<length;i++){
            B[i]=B[i-1]*A[i-1];
        }
        int temp=1;
        // //计算上三角
        for(int i=length-2;i>=0;i--){
            temp*=A[i+1];
            B[i]*=temp;
        }
        return B;
    }
}

3. 二维数组中的查找

题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

链接:https://www.nowcoder.com/questionTerminal/abc3fe2ce8e146608e868a70efebf62e
来源:牛客网

/* 思路
* 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,
* 因此从左下角开始查找,当要查找数字比左下角数字大时。右移
* 要查找数字比左下角数字小时,上移    
*/
public class Solution {
    public boolean Find(int target, int [][] array) {
        int row=array.length;
        int col=array[0].length;
        for(int i=row-1,j=0;i>=0&&j<col;){
            if(array[i][j]==target) return true;
            if(array[i][j]<target){
                j++;
                continue;
            }
           if(array[i][j]>target){
                i--;
               continue;
            }
        }
        return false;
    }
}
/*把每一行看成有序递增的数组,
利用二分查找,
通过遍历每一行得到答案,
时间复杂度是nlogn
*/
public class Solution {
    public boolean Find(int target, int [][] array) {
        for(int i=0;i<array.length;i++){
            int low=0;
            int high=array[i].length-1;
            while(low<=high){
                int mid=(low+high)/2;
                if(target>array[i][mid])
                    low=mid+1;
                else if(target<array[i][mid])
                    high=mid-1;
                else
                    return true;
            }
        }
        return false;
    }
}

1. 正则表达式匹配

题目描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

链接:https://www.nowcoder.com/questionTerminal/45327ae22b7b413ea21df13ee7d6429c
来源:牛客网

===========================递归的2种方法====================
===========================公共代码部分=====================

public static boolean match(char[] str, char[] pattern)
    {
        if(str == null || pattern == null)
            return false;
        return match(str, 0, pattern, 0);
    }
版本1:这里是剑指offer的解题思路
    /* 讨论2种:先看 * 再看 匹配
     * 前提:当pattern遍历完,return取决于str是否遍历完,str恰好遍历完才返回true,再接下来讨论
     *  1.若当前字符存在下一个字符,看下一个字符是否是 '*',如果是,有2种情况
     *      一:当前匹配
     *      1.1match(str,i + 1,pattern,j)//跳过str
     *      1.2match(str,i,pattern,j + 2)//跳过pattern
     *      1.3match(str,i + 1,pattern,j + 2)//这一种可以省略,相当于 1.1 + 1.2
     *      二:当前不匹配
     *      match(str,i,pattern,j + 2)//跳过pattern
     * 2.下一个不是 *
     *     当前匹配 return match(str,i + 1,pattern,j + 1)
     */

private  boolean match(char[] str, int i, char[] pattern, int j) {
       if(j == pattern.length)//pattern遍历完了
            return str.length == i;//如果str也完了,返回true,不然false
       //注意数组越界问题,一下情况都保证数组不越界
       if(j < pattern.length - 1 && pattern[j + 1] == '*') {//下一个是*
           if(str.length != i && //当前匹配
                   (str[i] == pattern[j] || pattern[j] == '.')) //匹配
               return match(str,i,pattern,j + 2)
                       || match(str,i + 1,pattern,j);
           else//当前不匹配
               return match(str,i,pattern,j + 2);
       }
       //下一个不是“*”,当前匹配
       if(str.length != i && (str[i] == pattern[j] || pattern[j] == '.'))
           return match(str,i + 1,pattern,j + 1);
        return false;
    }
//这里是第二个思路, 反过来,先看匹配 ,再看 *
    /*前提:当pattern遍历完,return取决于str是否遍历完,再接下来讨论
     * 1.先看当前字符是否匹配 记录first_isMatch
     * 2.再看下一个字符是否为 '*'
     *      2.1当前匹配first_isMatch && match(str,i + 1,pattern,j)
     *      2.2无论匹配与否match(str,i,pattern,j + 2)//跳过
     * 3.不匹配*,当前字符匹配的前提下,进入到下一个循环
     * else first_isMatch && match(str,i + 1,pattern,j + 1)
     */

 private boolean match1(char[] str, int i, char[] pattern, int j) {
        if(j == pattern.length)//pattern遍历完了
             return str.length == i;//如果str也完了,返回true,不然false
        //1.先看当前是否匹配
        boolean first_isMatch = (i != str.length) && (str[i] == pattern[j] || pattern[j] == '.'); 
        //2.再看后面是否有* pattern[j + 1] == '*'
        if(j < pattern.length - 1 && pattern[j + 1] == '*') {
            return match1(str, i, pattern, j + 2) || 
                        (first_isMatch && match1(str, i + 1, pattern, j));
        }else {
            return first_isMatch && match1(str, i + 1, pattern, j + 1);
        }
     }
 //===========================下面是动态规划的2种方法============================//
//公共部分
 /* 
     * 有了前面的认识,我们考虑用动态规划解题,动态规划有正向的和反向的,到底怎么取呢?
     * 看下前面的递归调用:match1(str, i + 1, pattern, j + 1)相当于 dp[i][j]=dp[i+1][j+1]
     * 适合反向遍历,于是,我们可以初始化boolean dp[len1+1][len2+1] 其中len1=str.length,len2=pattern.length
     * 初始化dp[len1][len2]=true,含义是:str=aaa 和pattern=aa* 从末尾开始匹配 "" 和 "" 一定为true
     * 这个时候开始循环
     * 1.外循环:因为我们要用aa*匹配aaa,以aaa为外循环,注意,从""开始匹配接下来a,aa,aaa
     * for(int i = len1;i>=0;i--)   
     * 2.内循环:拿aa*取匹配:匹配顺序 "*" "a*" "aa*",于是
     * for(int j = len2 - 1;j>=0;j--)
     * 循环体内部逻辑,参考递归调用:
* =============  *版本1:=============
   
     * 先看下一个是否是“*”,再看当前是否相等
     * 1.若下一个是"*",分为当前相等和当前不等
     *      1.1:当前相等dp[i][j]=dp[i][j+2] || dp[i+1][j]
     *      1.2:当前不等dp[i][j]=dp[i][j+2] 
     * 2.若不是"*",但是当前相等 d[i][j]= dp[i + 1][j + 1];
 

public static boolean matchDP1(char[] str, char[] pattern) {
        if(str == null || pattern == null)
            return false;
        boolean [][] dp = new boolean[str.length + 1][pattern.length + 1];
        dp[str.length][pattern.length] = true;
        //开始循环
        for (int i = str.length; i >= 0; i--) {//外循环:从空串开始匹配
           for (int j = pattern.length - 1; j >= 0; j--) {//内循环:从最后一个字符开始匹配
               if(j < pattern.length - 1 && pattern[j + 1] == '*') {
                   //1.1:当前相等
                   if(i < str.length && (str[i] == pattern[j] || pattern[j] == '.'))
                       dp[i][j] = dp[i][j + 2] || dp[i + 1][j];
                   else//1.2当前不等
                       dp[i][j] = dp[i][j + 2];
               }else {//若不是"*",看当前是否相等
                    if(i != str.length && (str[i] == pattern[j] || pattern[j] == '.')) {//当前相等
                        dp[i][j] = dp[i + 1][j + 1];
                    }
               }
            }
        }
        return dp[0][0];
    }
 * ============ *版本2.===============
    
     * 先看当前是否相等,再看下一个是否为“*”
     * 1.当前相等 立一个flag:
     * first_isMatch=i != str.length && (str[i] == pattern[j] || pattern[j] == '.')
     * 2.下一个是“*”
     *   无论当前是否相等,都可以跳过dp[i][j]=dp[i][j+2] ||
     *   或者,当前相等,那么 dp[i][j] = (first_isMatch && dp[i+1][j])
     *   综合得: dp[i][j] = dp[i][j+2] ||(first_isMatch && dp[i+1][j]);
     * 3.return dp[0][0]遍历完成

public static boolean matchDP2(char[] str, char[] pattern) {
        if(str == null || pattern == null)
            return false;
        boolean [][] dp = new boolean[str.length + 1][pattern.length + 1];
        dp[str.length][pattern.length] = true;
        //开始循环
        for (int i = str.length; i >= 0; i--) {//外循环:从空串开始匹配
           for (int j = pattern.length - 1; j >= 0; j--) {//内循环:从最后一个字符开始匹配
               //1.当前相等 立一个flag:相当于把if判断抽取出来,简化代码first_isMatch
               boolean first_isMatch = (i != str.length) && 
                                       (str[i] == pattern[j] || pattern[j] == '.');
               //2.下一个是“*”
               if(j < pattern.length - 1 && pattern[j + 1] == '*') {
                   dp[i][j] = dp[i][j + 2] || ( first_isMatch && dp[i + 1][j]);
               }else {
                   dp[i][j] = first_isMatch && dp[i + 1][j + 1];
               }
            }
        }
        return dp[0][0];
    }

2. 表示数值的字符串

题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

链接:https://www.nowcoder.com/questionTerminal/6f8c901d091949a5837e24bb82a731f2
来源:牛客网


链接:https://www.nowcoder.com/questionTerminal/6f8c901d091949a5837e24bb82a731f2
来源:牛客网

// 在 Java中都是数字
// 正则表达式解法
public class Solution {
    public boolean isNumeric(char[] str) {
        String string = String.valueOf(str);
        return string.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?");
    }
}
 
 
//参见剑指offer
public class Solution {
    private int index = 0;
  
    public boolean isNumeric(char[] str) {
        if (str.length < 1)
            return false;
         
        boolean flag = scanInteger(str);
         
        if (index < str.length && str[index] == '.') {
            index++;
            flag = scanUnsignedInteger(str) || flag;
        }
         
        if (index < str.length && (str[index] == 'E' || str[index] == 'e')) {
            index++;
            flag = flag && scanInteger(str);
        }
         
        return flag && index == str.length;
         
    }
     
    private boolean scanInteger(char[] str) {
        if (index < str.length && (str[index] == '+' || str[index] == '-') )
            index++;
        return scanUnsignedInteger(str);
         
    }
     
    private boolean scanUnsignedInteger(char[] str) {
        int start = index;
        while (index < str.length && str[index] >= '0' && str[index] <= '9')
            index++;
        return start < index; //是否存在整数
    }
}

3. 字符流中第一个不重复的字符

题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。

链接:https://www.nowcoder.com/questionTerminal/00de97733b8e4f97a3fb5c680ee10720
来源:牛客网


// 利用LinkedHashMap的有序性

import java.util.LinkedHashMap;
import java.util.Map;
 
public class Solution {
    private Map<Character, Integer> map = new LinkedHashMap<>();
     
    //Insert one char from stringstream
    public void Insert(char ch) {
        if (map.containsKey(ch)) {
            map.put(ch, map.get(ch) + 1);
        } else {
            map.put(ch, 0);
        }
    }
     
    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce() {
        for (Map.Entry<Character, Integer> set : map.entrySet()) {
            if (set.getValue() == 0) {
                return set.getKey();
            }
        }
        return '#';
    }
}

Linkedhashmap超强解释:https://blog.csdn.net/justloveyou_/article/details/71713781
在这里插入图片描述

链接:https://www.nowcoder.com/questionTerminal/00de97733b8e4f97a3fb5c680ee10720
来源:牛客网

Solution: 使用一个HashMap来统计字符出现的次数,同时用一个ArrayList来记录输入流,每次返回第一个出现一次的字符都是在这个ArrayList(输入流)中的字符作为key去map中查找。
 
import java.util.*;
public class Solution {
    HashMap<Character, Integer> map=new HashMap();
    ArrayList<Character> list=new ArrayList<Character>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if(map.containsKey(ch)){
            map.put(ch,map.get(ch)+1);
        }else{
            map.put(ch,1);
        }
         
        list.add(ch);
    }
     
    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {   char c='#';
        for(char key : list){
            if(map.get(key)==1){
                c=key;
                break;
            }
        }
         
        return c;
    }
}

4. 替换空格

题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

链接:https://www.nowcoder.com/questionTerminal/4060ac7e3e404ad1a894ef3e17650423
来源:牛客网

/*
问题1:替换字符串,是在原来的字符串上做替换,还是新开辟一个字符串做替换!
问题2:在当前字符串替换,怎么替换才更有效率(不考虑java里现有的replace方法)。
      从前往后替换,后面的字符要不断往后移动,要多次移动,所以效率低下
      从后往前,先计算需要多少空间,然后从后往前移动,则每个字符只为移动一次,这样效率更高一点。
*/
public class Solution {
    public String replaceSpace(StringBuffer str) {
        int spacenum = 0;//spacenum为计算空格数
        for(int i=0;i<str.length();i++){
            if(str.charAt(i)==' ')
                spacenum++;
        }
        int indexold = str.length()-1; //indexold为为替换前的str下标
        int newlength = str.length() + spacenum*2;//计算空格转换成%20之后的str长度
        int indexnew = newlength-1;//indexold为为把空格替换为%20后的str下标
        str.setLength(newlength);//使str的长度扩大到转换成%20之后的长度,防止下标越界
        for(;indexold>=0 && indexold<newlength;--indexold){ 
                if(str.charAt(indexold) == ' '){  //
                str.setCharAt(indexnew--, '0');
                str.setCharAt(indexnew--, '2');
                str.setCharAt(indexnew--, '%');
                }else{
                    str.setCharAt(indexnew--, str.charAt(indexold));
                }
        }
        return str.toString();
    }
}
链接:https://www.nowcoder.com/questionTerminal/4060ac7e3e404ad1a894ef3e17650423
来源:牛客网
//正则表达式的方法,\s表示空白字符也就是空格,制表符这些,至于最前面的\是用来转义第二个\的
public class Solution {
    public String replaceSpace(StringBuffer str) {
        return str.toString().replaceAll("\\s", "%20");
    }
}

1. 二进制中1的个数

题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
来源:牛客网

绝对最佳答案及分析:
public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while(n!= 0){
            count++;
            n = n & (n - 1);
         }
        return count;
    }
}
答案正确:恭喜!您提交的程序通过了所有的测试用例
分析一下代码: 这段小小的代码,很是巧妙。
如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,
原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,
它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。
这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。
如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.
那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
来源:牛客网

public class Solution {
    public int NumberOf1(int n) {
        return Integer.toBinaryString(n).replaceAll("0","").length(); }
}
链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
来源:牛客网
//     >>表示右移,如果该数为正,则高位补0,若为负数,则高位补1;

 //  >>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
public class Solution {
    public int NumberOf1(int n) {
        int sum=0;
        while(n!=0){
            sum+=n&1;//逐个判断低位是否为1;
            n=n>>>1;//无符号右移,例如从11101变成1110
        }
        return sum;
    }
}

已知一个数的补码,求原码的操作分两种情况:
(1)如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码。
(2)如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位为1,其余各位取反,然后再整个数加1。
例如,已知一个补码为11111001,则原码是10000111(-7):因为符号位为“1”,表示是一个负数,所以该位不变,仍为 “1”;其余7位1111001取反后为0000110;再加1,所以是10000111。

     * 10000000 00000000 00000000 00000101  --原码
	 * 11111111 11111111 11111111 11111010  --反码
	 * 11111111 11111111 11111111 11111011  --补码
链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
来源:牛客网

//超级简单容易理解                            //&(与)
// //把这个数逐次 右移 然后和1 与,
//就得到最低位的情况,其他位都为0,
//如果最低位是0和1与 之后依旧 是0,如果是1,与之后还是1。
//对于32位的整数 这样移动32次 就记录了这个数二进制中1的个数了 

class Solution {
public:
     int  NumberOf1(int n) {
         int count=0;
         for(int i=0;i<sizeof(int)*8;i++){
            if(n>>i&1)  
                count++;  
         }
         return count;
     }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值