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