本系列笔记主要记录笔者刷《程序员面试金典》算法的一些想法与经验总结,按专题分类,主要由两部分构成:经验值点和经典题目。其中重点放在经典题目上;
+
用时O( n2);而StringBuilder可以避免此问题,它会创建一个足以容纳所有字符串的可变长度数组;ACSII编码 | 常用字符 |
---|---|
48 | 0 |
57 | 9 |
65 | A |
90 | Z |
97 | a |
122 | z |
完整API请参考:个人总结的Java常用API手册汇总
构造方法:
String(byte[] bytes, int offset, int length)
:通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。//把字节数组的一部分转换为字符串。
String(char[] value, int offset, int count)
:分配一个新的 String,它包含取自字符数组参数一个子数组的字符。//把字符数组的一部分转换为字符串。
把字节/字符数组的一部分转换为字符串 offset:数组的开始索引 length:转换的字节个数 count:转换的字符个数
判断功能的方法:
boolean equalsIgnoreCase(String anotherString)
:将此字符串与指定对象进行比较,忽略大小写。获取功能的方法:
String concat(String str)
:将指定的字符串连接到该字符串的末尾。char charAt(int index)
:返回指定索引处的char值。int indexOf(String str)
:返回指定子字符串第一次出现在该字符串内的索引。String substring(int beginIndex)
:返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。String substring(int beginIndex, int endIndex)
:返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex。转换功能的方法:
char[] toCharArray()
:将此字符串转换为新的字符数组。
byte[] getBytes()
:使用平台的默认字符集将该String编码转换为新的字节数组。
String replaceAll(String regex, String replacement)
:成功则返回替换的字符串,失败则返回原始字符串。其中regex为匹配此字符串的正则表达式;replacement为用来替换每个匹配项的字符串。
String replace(CharSequence target, CharSequencere placement)
:将与target匹配的字符串使用replacement字符串替换。
CharSequence是一个接口,也是一种引用类型。作为参数类型,可以把String对象传递到方法中。
分割功能的方法:
String[] split(String regex)
:将此字符串按照给定的regex(规则)拆分为字符串数组。
split方法的参数其实是一个“正则表达式”,如果按照英文句点“.”进行切分,必须写"\."。
将基本数据型态转换成String的static方法:
String.valueOf(Object o)
: 将 Object 变量 o 转换成字符串,等于 obj.toString()。
Object可以是: char、char[]、double、float等。
String.valueOf(char[] data, int offset, int count)
: 将 char 数组 data 中 由 data[offset] 开始取 count 个元素 转换成字符串。将String转换成基本数据型态的方法(Character除外):
static Object parseObject(String s)
:将字符串参数转换为对应的byte基本类型。
Object可以是: byte、short、int、long、float、double、boolean等。
Arrays.sort(int[] a, int fromIndex, int toIndex)
:对数组部分排序,也就是对数组a的下标从fromIndex到toIndex-1的元素排序;如果要从大到小需要实现Comparator接口;
Arrays.sort(obj)
:可以对obj对象排序;
obj对象一般是数组,包括各种数组;
private Map<Character, Integer> getMap(String str) {
Map<Character, Integer> map = new HashMap<>();
char[] chars = str.toCharArray();
for (char aChar : chars) {
map.put(aChar, map.getOrDefault(aChar, 0) + 1);
}
return map;
}
主要就两种方法:
- 第一种是通过keySet()方法获得key,再通过map.get(key)方法,得到值;
- 第二种是先用entrySet()方法转为Set类型,其中set的每一个元素值就是map的一个键值对,即Map.Entry
;
//方法一:普通的foreach循环,使用keySet()方法,遍历key
for(Integer key : map.keySet()){
System.out.println("key = " + key);
System.out.println("Value = " + map.get(key));
}
//方法二:把所有的键值对装入迭代器中,然后遍历迭代器
Iterator<Map.Entry<Integer,String>> it = map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer,String> entry=it.next();
System.out.println("key = "+entry.getKey());
System.out.println("Value = "+entry.getValue());
}
//方法三:分别得到key和value
for(Integer obj : map.keySet()){
System.out.println("key = " + obj);
}
for(String obj : map.values()){
System.out.println("value = " + obj);
}
//方法四,entrySet()方法
for (Map.Entry<Integer,String> entry : map.entrySet()){
System.out.println("key = " + entry.getKey());
System.out.println("value = " + entry.getValue());
}
char[] c = S.toCharArray()
的索引效率更高;s.charAt(i)
方法索引多了方法栈和越界检查的消耗;public boolean isUnique(String astr) {
Map<Character, Integer> map = new HashMap<>();
for(int i = 0; i < astr.length(); i++ ){
if(map.containsKey(astr.charAt(i))){
return false;
}
map.put(astr.charAt(i), i);
}
return true;
}
public boolean isUnique(String astr) {
if( astr.length() > 128 ){
return true;
}
boolean[] arr = new boolean[128];
for (int i = 0; i < astr.length(); i++) {
int c = (int)astr.charAt(i);
if ( arr[c] ){
return false;
}
arr[c] = true;
}
return true;
}
public boolean isUnique(String astr) {
int mark = 0;
for (int i = 0; i < astr.length() ; i++) {
//移动距离
int move = (int)astr.charAt(i) - 'a';
if ((mark & (1<< move) )!=0){
return false;
}else {
mark |=(1<<move);
}
}
return true;
}
public boolean isUnique(String astr) {
if( astr == null || "".equals(astr)){
return true;
}
int left = 0;
int rigth = astr.length();
for(int i = 0; i < astr.length(); i++){
for(int j = i+1; j < astr.length(); j++){
if(astr.charAt(i) == astr.charAt(j)){
return false;
}
}
}
return true;
}
public boolean CheckPermutation(String s1, String s2) {
// 将字符串转换成字符数组
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
// 对字符数组进行排序
Arrays.sort(c1);
Arrays.sort(c2);
// 再将字符数组转换成字符串,比较是否相等
return new String(c1).equals(new String(c2));
}
public boolean CheckPermutation(String s1, String s2) {
if (s1.length() != s2.length()) {
return false;
}
char[] s1Chars = s1.toCharArray();
Map<Character, Integer> s1Map = getMap(s1);
Map<Character, Integer> s2Map = getMap(s2);
for (char s1Char : s1Chars) {
if (!s2Map.containsKey(s1Char) || s2Map.get(s1Char) != s1Map.get(s1Char)) {
return false;
}
}
return true;
}
// 统计指定字符串str中各字符的出现次数,并以Map的形式返回
private Map<Character, Integer> getMap(String str) {
Map<Character, Integer> map = new HashMap<>();
char[] chars = str.toCharArray();
for (char aChar : chars) {
map.put(aChar, map.getOrDefault(aChar, 0) + 1);
}
return map;
}
用数组来统计每个字符的出现次数;
public boolean CheckPermutation(String s1, String s2) {
if (s1.length() != s2.length()) {
return false;
}
int[] c1 = count(s1);
int[] c2 = count(s2);
for (int i = 0; i < c1.length; i++) {
if (c1[i] != c2[i]) {
return false;
}
}
return true;
}
private int[] count(String str) {
int[] c = new int[26];
char[] chars = str.toCharArray();
for (char aChar : chars) {
c[aChar - 'a']++;
}
return c;
}
public boolean CheckPermutation(String s1, String s2) {
int sum1 = 0;
int sum2 = 0;
if(s1.length() != s2.length()) {
return false;
}
for(int i = 0; i < s1.length(); i++){
sum1 += s1.charAt(i);
sum2 += s2.charAt(i);
}
return (sum1 == sum2);
}
public String replaceSpaces(String S, int length) {
return S.substring(0, length).replaceAll(" ", "%20");
}
String substring(int beginIndex, int endIndex)
:返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex。String replaceAll(String regex, String replacement)
:成功则返回替换的字符串,失败则返回原始字符串。其中regex为匹配此字符串的正则表达式;replacement为用来替换每个匹配项的字符串。public String replaceSpaces(String S, int length) {
if(S == null || length < 0){
return null;
}
char[] c = S.toCharArray();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < c.length; i++){
if( c[i] == ' ' && length == 0){
return sb.toString();
}
if(c[i] == ' '){
sb.append("%20");
} else {
sb.append(c[i]);
}
length--;
}
return sb.toString();
}
public String replaceSpaces(String S, int length) {
//先把字符串转化为字符数组
char[] chars = S.toCharArray();
int index = chars.length - 1;
for (int i = length - 1; i >= 0; i--) {
//如果遇到空格就把他转化为"%20"
if (chars[i] == ' ') {
chars[index--] = '0';
chars[index--] = '2';
chars[index--] = '%';
} else {
chars[index--] = chars[i];
}
}
return new String(chars, index + 1, chars.length - index - 1);
}
public boolean canPermutePalindrome(String s) {
if(s == null){
return false;
}
Map<Character, Integer> map = getMap(s);
int single = 0;
for( Map.Entry<Character, Integer> entry : map.entrySet()){
if( entry.getValue() % 2 == 1){
single++;
}
}
if((s.length() % 2 == 0) && (single == 0)){
return true;
}
if((s.length() % 2 == 1) && (single == 1)){
return true;
}
return false;
}
// 统计指定字符串str中各字符的出现次数,并以Map的形式返回
private Map<Character, Integer> getMap(String str) {
Map<Character, Integer> map = new HashMap<>();
char[] chars = str.toCharArray();
for (char aChar : chars) {
map.put(aChar, map.getOrDefault(aChar, 0) + 1);
}
return map;
}
public boolean canPermutePalindrome(String s) {
Set<Character> set = new HashSet<>();
for (char ch : s.toCharArray()) {
//set的add方法如果返回false,表示已经有了,就删除
if (!set.add(ch)) {
set.remove(ch);
}
}
return set.size() <= 1;
}
HashSet的规则:
hashCode()
产生一个哈希值);
equals()
方法比较;
equals()
方法返回true,说明新添加的元素与集合中已有的某个元素的属性值相同,那么新添加的元素不存入集合;equals()
方法返回false,说明新添加的元素与集合中已有的元素的属性值都不同,,那么新添加的元素存入集合;set.size() <= 1:
public boolean canPermutePalindrome(String s) {
int[] map = new int[128];
int count = 0;
for (char ch : s.toCharArray()) {
if ((map[ch]++ & 1) == 1) {
count--;
} else {
count++;
}
}
return count <= 1;
}
执行时间:100.00%;内存消耗:76.73%;
结果其实与字符的奇偶性无关,遇到不同count++,遇到相同count–,如果满足回文,count的结果只有可能是0或1;
有点类似于HashSet的唯一性;
public boolean canPermutePalindrome(String s) {
long highBitmap = 0;
long lowBitmap = 0;
for (char ch : s.toCharArray()) {
if (ch >= 64) {
highBitmap ^= 1L << ch - 64;
} else {
lowBitmap ^= 1L << ch;
}
}
return Long.bitCount(highBitmap) + Long.bitCount(lowBitmap) <= 1;
}
public boolean oneEditAway(String first, String second) {
if( first == null && second == null){
return true;
}
if( first == null ){
return false;
}
if( second == null ){
return false;
}
if(first.length() == second.length()){
//判断替换
int count = 0;
for(int i = 0; i < first.length(); i++){
if( first.charAt(i) != second.charAt(i) ){
count++;
}
}
return count <= 1;
} else {
//判断增删
//替换找最长
String longger;
String shortter;
if( first.length() > second.length() ){
longger = first;
shortter = second;
} else {
longger = second;
shortter = first;
}
if(longger.length() == 1 && shortter.length() == 0){
return true;
}
//用count记录不同次数
int count = 0;
int j = 0;
for( int i = 0; i < shortter.length() ; i++, j++){
if( longger.charAt(j) != shortter.charAt(i) ){
count++;
i--;
}
if( count > 1){
return false;
}
}
//判断长字符串最后一个字符是否不同
if( j == longger.length() - 1){
count++;
if( count > 1){
return false;
}
}
return j == longger.length()-1 || j == longger.length();
}
}
if(second.length()>first.length) return oneEditAway(second, first)
;public boolean oneEditAway(String first, String second) {
if (first == null || second == null) return false;
int len1 = first.length();
int len2 = second.length();
if (Math.abs(len1 - len2) > 1) return false;
// 保持第一个比第二个长
if (len2 > len1) return oneEditAway(second, first);
for (int i = 0; i < len2; i++){
if (first.charAt(i) != second.charAt(i)){
//如果是长度相同字符串,那就比较下一个,如果长度不一样,那就从该字符开始进行比较。
return first.substring(i + 1).equals(second.substring(len1 == len2 ? i + 1 : i));
}
}
return true;
}
public boolean oneEditAway(String word1, String word2) {
int length1 = word1.length();
int length2 = word2.length();
int dp[][] = new int[length1 + 1][length2 + 1];
for (int i = 0; i <= length1; i++) {
dp[i][0] = i;//边界条件,相当于word1的删除操作
}
for (int i = 0; i <= length2; i++) {
dp[0][i] = i;//边界条件,相当于word1的添加操作
}
for (int i = 1; i <= word1.length(); i++) {
for (int j = 1; j <= length2; j++) {//下面是上面分析的递推公式
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
}
}
}
return dp[length1][length2] <= 1;
}
public String compressString(String S) {
if( S == null || "".equals(S)){
return S;
}
char[] chs = S.toCharArray();
char cache = chs[0];
StringBuilder sb = new StringBuilder();
sb.append(chs[0]);
int count = 0;
for(int i = 0; i < S.length(); i++){
if( cache != chs[i] ){
sb.append(count);
sb.append(chs[i]);
cache = chs[i];
count = 1;
} else {
count++;
}
if( i == S.length() -1 ){
sb.append(count);
}
}
String result = sb.toString();
return result.length() < S.length() ? result : S;
}
public void rotate(int[][] matrix) {
int line = matrix.length;
int row = matrix[0].length;
if(line == 0){
return;
}
int[][] result = new int[row][line];
for( int i = 0; i < line; i++){
for( int j = 0; j < row; j++){
result[j][line-1-i] = matrix[i][j];
}
}
for(int i = 0; i < row; i++){
for( int j = 0; j < line; j++){
matrix[i][j] = result[i][j];
}
}
}
public void rotate(int[][] matrix) {
int n = matrix.length;
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < (n + 1) / 2; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = temp;
}
}
}
public void rotate(int[][] matrix) {
int n = matrix.length;
// 水平翻转
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < n; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n - i - 1][j];
matrix[n - i - 1][j] = temp;
}
}
// 主对角线翻转
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
}
public void setZeroes(int[][] matrix) {
int line = matrix.length;
int row = matrix[0].length;
if(line == 0){
return;
}
boolean[][] isZero = new boolean[line][row];
for(int i = 0; i < line; i++){
for(int j =0; j < row; j++){
//没有被标记
if( !isZero[i][j] ){
//处理0情况并标记
if(matrix[i][j] == 0){
for(int k = 0; k < row; k++){
if(matrix[i][k] != 0){
matrix[i][k] = 0;
isZero[i][k] = true;
}
}
for(int k = 0; k < line; k++){
if(matrix[k][j] != 0 ){
matrix[k][j] = 0;
isZero[k][j] = true;
}
}
}
}
}
}
}
public void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean flagCol0 = false, flagRow0 = false;
//检查第一列是否有0
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) {
flagCol0 = true;
}
}
//检查第二列是否有0
for (int j = 0; j < n; j++) {
if (matrix[0][j] == 0) {
flagRow0 = true;
}
}
//检查其他元素是否有0,有0则根据下标在第一行与第一列置0
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][j] == 0) {
matrix[i][0] = matrix[0][j] = 0;
}
}
}
//根据第一行与第一列的值置空
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
//置空第一列
if (flagCol0) {
for (int i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
//置空第一行
if (flagRow0) {
for (int j = 0; j < n; j++) {
matrix[0][j] = 0;
}
}
}
public void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean flagCol0 = false;
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) {
flagCol0 = true;
}
for (int j = 1; j < n; j++) {
if (matrix[i][j] == 0) {
matrix[i][0] = matrix[0][j] = 0;
}
}
}
for (int i = m - 1; i >= 0; i--) {
for (int j = 1; j < n; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
if (flagCol0) {
matrix[i][0] = 0;
}
}
}
public boolean isFlipedString(String s1, String s2) {
if(s1.length() != s2.length()){
return false;
}
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
int[] count = new int[128];
for( int i = 0; i < s1.length(); i++){
count[c1[i]]++;
count[c2[i]]--;
}
for( int i = 0; i < 128; i++){
if(count[i] != 0){
return false;
}
}
return true;
}
public boolean isFlipedString(String s1, String s2) {
if(s1.length() != s2.length()) {
return false;
}
String s = s2 + s2;
return s.contains(s1);
}