2021-6-12金典笔记00

笔记00

_01_判断字符串是否唯一

实现一个算法,确定一个字符串 s 的所有字符是否全都不同。

示例 1:

输入: s = “leetcode”
输出: false
示例 2:

输入: s = “abc”
输出: true
限制:

0 <= len(s) <= 100
如果你不使用额外的数据结构,会很加分。

package LeetCode._面试经典.笔记00;

import org.junit.Test;

public class _01_判断字符串是否唯一 {
    public boolean isUnique01(String astr) {
        if (astr==null) return true;
        if (astr.length()==0) return true;
         int[] flag=new int[256];
         char[] chars = astr.toCharArray();
         boolean isU=true;
         for (char aChar : chars) {
             if (flag[aChar]!=0) isU=false;
             flag[aChar]++;
         }
         return isU;
    }
    /*
    方法一样:不过用一个整数的位代表26(有限制26个小写字符)种字符
    * */
    public boolean isUnique(String astr) {
        if (astr==null) return true;
        if (astr.length()==0) return true;
        int flag=0;
        for (int i=0;i<astr.length();i++){
            if ((flag& 1<<(astr.charAt(i)-'a'))!=0) return false;
            flag|=1<<(astr.charAt(i)-'a');
        }
        return true;
    }
}

_02_判断是否互为字符重排

给定两个字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。

示例 1:

输入: s1 = “abc”, s2 = “bca”
输出: true
示例 2:

输入: s1 = “abc”, s2 = “bad”
输出: false
说明:

0 <= len(s1) <= 100
0 <= len(s2) <= 100

package LeetCode._面试经典.笔记00;

public class _02_判断是否互为字符重排 {

    //256辅助数组
    public boolean CheckPermutation(String s1, String s2) {
       if (s1==null||s2==null) return false;
       //长度不相等肯定不是
       if (s1.length()==0&&s2.length()==0) return true;
       if ((s1.length()^s2.length())!=0) return false;

        int[] memory=new int[256];
        char[] c1 = s1.toCharArray();
        char[] c2 = s2.toCharArray();
        for (int i=0;i<c1.length;i++){
            memory[c1[i]]++;
            memory[c2[i]]--;
        }
        for (int i : memory) {
            if (i!=0) return false;
        }
        return true;
    }


}

_03_URL化

URL化。编写一种方法,将字符串中的空格全部替换为%20。假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的“真实”长度。(注:用Java实现的话,请使用字符数组实现,以便直接在数组上操作。)

示例 1:

输入:"Mr John Smith ", 13
输出:“Mr%20John%20Smith”
示例 2:

输入:" “, 5
输出:”%20%20%20%20%20"

提示:

字符串长度在 [0, 500000] 范围内。

package LeetCode._面试经典.笔记00;

import org.junit.Test;

import java.util.Arrays;
import java.util.HashMap;

public class _03_URL化 {
    public String replaceSpaces01(String S, int length) {
        if (S==null) return null;
        if (S.length()==0||S.length()<length) return "\0";

        char[] chars = S.toCharArray();
        StringBuilder res=new StringBuilder();

        for (int i=0;i<length;i++){
            if (chars[i]==' ') res.append("%20");
            else res.append(chars[i]);
        }
        return res.toString();
    }
    /*
    另外一种时间空间效率更高的解法:先统计空格的个数
    * */
    public String replaceSpaces(String S, int length) {
        if (S==null) return null;
        if (S.length()==0||S.length()<length) return "\0";

        char[] chars = S.toCharArray();
        int countSP=0;
        int i=0;
        for (;i<length;i++){
            if (chars[i]==' ') countSP++;
        }
        int len=length+countSP*2;
        char[] res=new char[len];
        i=0;
        for (int j=0;j<len;){
            if (chars[i]==' '){
                res[j]='%';
                res[j+1]='2';
                res[j+2]='0';
                j+=3;
            }
            else res[j++]=chars[i];
            i++;
        }
        return new String(res);//字符数组转字符串正确方式是直接new
    }

    @Test
    public void test(){
        new HashMap<>();
        String s="Mr John Smith    ";
        String s1=replaceSpaces(s,13);
        System.out.println(s1);
    }

}

_04_回文序列

给定一个字符串,编写一个函数判定其是否为某个回文串的排列之一。

回文串是指正反两个方向都一样的单词或短语。排列是指字母的重新排列。

回文串不一定是字典当中的单词。

示例1:

输入:“tactcoa”
输出:true(排列有"tacocat"、“atcocta”,等等)

package LeetCode._面试经典.笔记00;

public class _04_回文序列 {

    /*
    首先应该询问面试官的是字符是ASCII字符还是Unicode统一编码字符
    ASCII字符128个(拓展的ASCII码256个)
    所有偶数长度的字符(不包括非字母字符)的字符必须出现偶数次;
    所有奇数长度的字符的字符只能有一个出现奇数数次
    归结为:1个回文串包含不超过1个奇数个的字符

    优化:省略1次for循环,增加额外代码,但是此次优化却不一定就比原来的快
    * */
    public boolean canPermutePalindrome01(String s) {
          if (s==null) return false;
          if (s.length()<=0) return true;
          int[] res=new int[256];
          char[] chars = s.toCharArray();
          int times=0;
          for (int i=0;i<chars.length;i++){
              res[chars[i]]++;
              if ((res[chars[i]]&1)==1) times++;
              else times--;
          }
          /*
          for (int i=0;i<256;i++){
            if ((res[i]&1)==0) continue;
            else times++;
          }*/
          return times<=1;
    }
    /*
    不采用数据结构:异或模拟开灯和关灯的操作,而不需要去管出现偶数次还是奇数次
    在128位的字符中,如果是int(4字节=32比特)类型需要4位置(32*4=128),
    但是如果用long(8字节=64比特)类型,只需要两位就行了,一个记录0-63,一个记录64-127
    最后判断大于1的个数,如果大于1的话就不能构成回文序列
    * */
    public boolean canPermutePalindrome(String s) {
        if (s==null) return false;
        if (s.length()<=0) return true;
        long highBitmap=0;//64-127
        long lowBitmap=0;//0-63
        for (char c : s.toCharArray()) {
            if (c>=64) highBitmap^=1l<<c-64;
            else lowBitmap^=1l<<c;
        }
        return Long.bitCount(highBitmap)+Long.bitCount(lowBitmap)<=1;
    }

}

_05_一次编辑

字符串有三种编辑操作:插入一个字符、删除一个字符或者替换一个字符。 给定两个字符串,编写一个函数判定它们是否只需要一次(或者零次)编辑。

示例 1:

输入:
first = “pale”
second = “ple”
输出: True

示例 2:

输入:
first = “pales”
second = “pal”
输出: False

package LeetCode._面试经典.笔记00;

public class _05_一次编辑 {
    /*
    首先思考替换,插入,删除的意义
    替换:仅1位不同
    插入:和删除相反
    删除:除去1位后相同

     长度大于1,false
     替换
     1)长度相同:找到第1个不同且后面要都相同
     插入/删除
     2)长度不同:找到第1个不同,短的那个等1位后面都要相同
     时间复杂度:O(N)  O(1)
    * */
    public boolean oneEditAway(String first, String second){
       if (first==null||second==null) return false;
       if (first.length()==0&&second.length()==0) return true;
       int n1=first.length();
       int n2=second.length();
       int abs=n1-n2;
       if (abs<-1||abs>1) return false;
       /*String max=null;
       String min=null;
       if (n1>=n2){
           max=first;
           min=second;
       }else {
           max=second;
           min=first;
       }
       int n=Math.max(n1,n2);
       保持第一个最长:往回掉一次就够了
       */
       if (n2>n1) return oneEditAway(second,first);
       for (int i=0;i<n2;i++){
           if (first.charAt(i)!=second.charAt(i)){
               //如果长度相同的字符串,那就比较下一个 都是i+1
               if (n1==n2) return first.substring(i+1).equals(second.substring(i+1));
               //如果长度不相同,那就从该字符开始比较  i+1 i
               else return first.substring(i+1).equals(second.substring(i));
           }
       }
       return true;//防止不进for循环,空和1个字符的情况
    }
}

_06_字符串压缩

字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。

示例1:

输入:“aabcccccaaa”
输出:“a2b1c5a3”
示例2:

输入:“abbccd”
输出:“abbccd”
解释:“abbccd"压缩后为"a1b2c2d1”,比原字符串长度更长。
提示:

字符串长度在[0, 50000]范围内。

package LeetCode._面试经典.笔记00;

public class _06_字符串压缩 {

    /*
    双指针+StringBuilder  O(N^2)
    for循环内的字符串拷贝需要O(N)时间复杂度(流来处理,当然可能会快一些)
    * */
    public String compressString(String S){
       if (S==null) return null;
       if (S.length()==0) return S;
       int n=S.length();
        StringBuilder sb = new StringBuilder(n);//提前初始化容量,否则每次隐式扩容放2两倍浪费空间
        int i=0,j=0;//首尾指针
        while (j<n){
            while (j<n&&S.charAt(j)==S.charAt(i)) j++;
            sb.append(S.charAt(i));
            sb.append(j-i);//j的位置已经是下一个字符了
            i=j;
        }
        String res=sb.toString();
        if (res.length()<S.length()) return res;
        else return S;
    }
}

_07_矩阵旋转

给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。

不占用额外内存空间能否做到?

示例 1:

给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],

原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
示例 2:

给定 matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],

原地旋转输入矩阵,使其变为:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]

package LeetCode._面试经典.笔记00;

import org.junit.Test;

public class _07_矩阵旋转 {
    /*
    要求:矩阵顺时针旋转

    用辅助数组:对行一次旋转成列就能到正确的位置
       主要理解2句话
       1)第一行变成倒数第一列,
       2)第一行的第x个元素变成倒数第一列的第x个元素。
       matrix_new[j][n-1-i]=matrix[i][j];

    不用辅助空间:
    1.原地旋转 在上述方法的基础上考虑层次,而且每次只旋转4元素,其实就是上述的逆向思维
      它去替换谁: matrix[j][n-1-i] = matrix[i][j]
        ||
        V
      谁来替换它: matrix[i][j]= matrix[n-1-j][i]
      另外3个就一次类推了
                matrix[n-1-j][i] = matrix[n-1-i][n-1-j]
                matrix[n-1-i][n-1-j] = matrix[j][n-1-i]
                matrix[j][n-1-i] = matrix[i][j]


    2.翻转代替旋转
       水平翻转:m[i][j]=>m[n-1-i][j]
       对角线翻转:m[i][j]=>m[j][i]
       m[i][j]=>m[n-1-i][j]=>m[j][n-1-i]
       与上面的式子是一样的

    * */
    public void rotate01(int[][] matrix) {
       if (matrix==null) return;
       int n=matrix.length;
       for (int i=0;i<n/2;i++){//圈数控制
           for (int j=i;j<n-1-i;j++){//每一圈每一行需要旋转的范围,最后一个别转
               //倒着的顺时针
               int temp=matrix[i][j];
               matrix[i][j]= matrix[n-1-j][i];
               matrix[n-1-j][i] = matrix[n-1-i][n-1-j];
               matrix[n-1-i][n-1-j] = matrix[j][n-1-i];
               matrix[j][n-1-i]=temp;
           }
       }
    }

    public void rotate(int[][] matrix) {
        if (matrix==null) return;
        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-1-i][j];
                matrix[n-1-i][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;
            }
        }
    }

}

_08_零矩阵

编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。

示例 1:

输入:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
输出:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
示例 2:

输入:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
输出:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]

package LeetCode._面试经典.笔记00;

import java.util.Arrays;

public class _08_零矩阵 {

    //利用数组的第一行和第一列做标记,使空间复杂度为O(1)
    public void setZeroes(int[][] matrix) {
       if (matrix==null) return;
       if (matrix.length==0) return;;
       boolean row0=false;
       boolean col0=false;
       int n=matrix.length;
       int m=matrix[0].length;
       //记录第1列是否有0
       for (int i=0;i<n;i++){
           if (matrix[i][0]==0){
               col0=true;
               break;
           }
       }
       //记录第1行是否有0
       for (int j=0;j<m;j++){
           if (matrix[0][j]==0){
               row0=true;
               break;
           }
       }
       //标记第1列第1行
       for (int i=1;i<n;i++){
           for (int j=1;j<m;j++){
               if (matrix[i][j]==0){
                   matrix[i][0]=0;
                   matrix[0][j]=0;
               }
           }
       }
       //行清零
       for (int i=1;i<n;i++){
           if (matrix[i][0]==0){
               for (int j=1;j<m;j++) matrix[i][j]=0;
           }
       }
       //列清零
       for (int j=1;j<m;j++){
           if (matrix[0][j]==0) {
               for (int i=1;i<n;i++) matrix[i][j]=0;
           }
       }
       //处理第1行第1列
       if (row0){
           for (int j=0;j<m;j++) matrix[0][j]=0;
       }
       if (col0){
           for (int i=0;i<n;i++) matrix[i][0]=0;
       }

    }

}

_09_字符串轮转

字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。

示例1:

输入:s1 = “waterbottle”, s2 = “erbottlewat”
输出:True
示例2:

输入:s1 = “aa”, s2 = “aba”
输出:False
提示:

字符串长度在[0, 100000]范围内。

package LeetCode._面试经典.笔记00;

import org.junit.Test;

public class _09_字符串轮转 {

    /*
    s1=xy
    s2=yx
    yx是xyxy的子串=》s2是s1s1的子串
    * */
    public boolean isFlipedString(String s1, String s2) {
        if (s1==null||s2==null) return false;
        if ((s1.length()^s2.length())!=0) return false;
        String s=s1+s1;
        return s.contains(s2);
    }
    @Test
    public void test(){
        String s="abace";
        System.out.println(s.contains("bc"));
        System.out.println(s.contains("bac"));
        System.out.println(s.contains("abacee"));
    }

}

_10_移除链表的重复节点

编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。

示例1:

输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]
示例2:

输入:[1, 1, 1, 1, 2]
输出:[1, 2]
提示:

链表长度在[0, 20000]范围内。
链表元素在[0, 20000]范围内。
进阶:

如果不得使用临时缓冲区,该怎么解决?

package LeetCode._面试经典.笔记00;

import java.util.HashSet;

public class _10_移除链表的重复节点 {
    public class ListNode {
        int val;
        ListNode next;
        ListNode(int x) { val = x; }
    }
    //使用辅助数据结构散列表HashSet 时间复杂度O(N) 空间复杂度O(N)
    public ListNode removeDuplicateNodes01(ListNode head) {
        ListNode p=head;
        ListNode pre=head;
        HashSet<Integer> set = new HashSet<>();
        while (p!=null){
            int value=p.val;
            if (set.contains(value)){
                p=p.next;
                pre.next=p;
                continue;
            }
            set.add(value);
            pre=p;
            p=p.next;
        }
        return head;
    }
    //不使用辅助数据结构:3个指针  时间复杂度O(N^2) 空间复杂度O(1)
    public ListNode removeDuplicateNodes(ListNode head) {
        if (head==null) return null;
        ListNode p1=head;
        ListNode p2=p1;//前驱节点
        ListNode p3=null;
        while (p2!=null){
            p3=p2.next;
            while (p3!=null){
                if (p1.val==p3.val){
                    p3=p3.next;
                    p2.next=p3;
                    continue;
                }
                p2=p3;
                p3=p3.next;
            }
            p1=p1.next;//处理下1个节点
            p2=p1;
        }
        return head;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值