zoukankan      html  css  js  c++  java
  • ArrayAndString(数组和字符串)

    1.实现一个算法,确定一个字符串的所有字符是否全都不同。假使不允许使用额外的数据结构,又该怎么处理?

    public class UniqueChars {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String string = "abcdefgfedcba";
            System.out.print(isUniqueChars(string));
                
        }
        public static boolean isUniqueChars(String str) {
            if (str.length() > 256) {
                return false;
            }
            boolean[] char_set = new boolean[256];
            for (int i = 0; i < str.length(); i++) {
                int val = str.charAt(i);
                if (char_set[val]) {
                    return false;
                }
                char_set[val] = true;
            }
            return true;
        }
    
    }
    View Code

    注意:向面试官确认上面的字符串是ASCII字符串还是Unicode字符串。若不是ASCII字符串需扩大存储空间,但其余逻辑不变。

              这里假定是ASCII字符串。首先做一个优化,若字符串长度大于字母表中的字符个数,就直接返回false。毕竟,若字母表只有256个字符,字符串里就不可能有280个各不相同的字符。

               然后构建一个布尔值的数组,索引值i对应的标记指示该字符串是否含有字母表第i个字符。若这个字符第二次出现,则立即返回false。时间复杂度o(n),空间复杂度o(1)。

    若不允许使用额外的数据结构:

    (1)将字符串中的每一个字符与其余字符进行比较。时间复杂度为o(n2),空间复杂度o(1)。

    public class UniqueChars {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String string = "abcdefgfedcba";
            System.out.print(isUniqueChars(string));
                
        }
       
        public static boolean isUniqueChars(String str) {
            if (str.length() > 256) {
                return false;
            }
            for(int i = 0; i < str.length(); i++) {
                for(int j = i + 1; j < str.length(); j++) {
                    if(str.charAt(i) == str.charAt(j)) return false;
                }
            }
            return true;
        }
    }
    View Code

    (2)若允许修改输入字符串,可以在o(nlogn)的时间里对字符串排序,然后线性检查其中有无相邻字符完全相同的情况。

    2.用Java实现void reverse(char* str)函数,即反转一个null结尾的字符串。

    package ArrayAndString;
    
    public class Reverse {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String string = "abcdefg";
            System.out.println(reverseString2(string));
        }
        //最简单的方法
        public static String reverseString(String iniString) {
            // write code here
            StringBuffer tmp = new StringBuffer(iniString);
            tmp = tmp.reverse();
            return tmp.toString();
        }
        //最常用的方法
        public static String reverseString2(String iniString) { 
             char[] array = iniString.toCharArray(); 
             String reverse = "";  //注意这是空串,不是null
             for (int i = array.length - 1; i >= 0; i--) { 
                 reverse += array[i];
             }
             return reverse; 
         } 
    
    }
    View Code

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

    解法一:对字符串排序后进行比较,若它们拥有相同顺序的字符,即互为变位词。

    import java.util.*;
    
    public class IsAnagram {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String string1 = "aceg";
            String string2 = "cega";
            System.out.println(permutation(string1, string2));    
        }
        
        public static String sort(String s) {
            char[] content = s.toCharArray();
            Arrays.sort(content);
            return new String(content);
        }
        
        public static boolean permutation(String s, String t) {
            if (s.length() != t.length()) {
                return false;
            }
            return sort(s).equals(sort(t));
        }
    
    }
    View Code

    解法二:利用变位词的定义--组成两个单词的字符数相同,遍历字母表,计算每个字符出现的次数,然后比较这两个数组。

    public class IsAnagram {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String string1 = "aceg";
            String string2 = "cega";
            System.out.println(permutation(string1, string2));    
        }
        public static boolean permutation(String s, String t) {
            if (s.length() != t.length()) {
                return false;
            }
            
            int[] letters = new int[256];
            char[] s_array = s.toCharArray();
            for (char c : s_array) {
                letters[c]++;
            }
            for (int i = 0; i < t.length(); i++) {
                int c = (int) t.charAt(i);
                if (--letters[c] < 0) {
                    return false;
                }
            }
            return true;
        }
    
    }
    View Code

    注意:向面试官确认 变位词是否区分大小写 以及 是否要考虑空白字符。

              这里假定变位词比较区分大小写,空白也要考虑在内,是ASCII字符串。首先做一个优化,比较两个字符串的长度,只要长度不同就不可能是变位词。

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

    思路:进行两次扫描。第一次扫描先数出字符串中有多少空格,从而算出最终的字符串有多长。第二次扫描真正开始反向编辑字符串,检测到空格则将%20复制到下一个位置,若不是空白,就复制原先的字符。

    public class ReplaceString {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String str = "abc d e f";
            char[] arr = new char[str.length() + 3 * 2 + 1];
            for (int i = 0; i < str.length(); i++) {
                arr[i] = str.charAt(i);
            }
            replaceSpaces(arr, str.length());    
            System.out.println(""" + charArrayToString(arr) + """);
    
        }
        
        public static String charArrayToString(char[] array) {
            StringBuilder buffer = new StringBuilder(array.length);
            for (char c : array) {
                if (c == 0) {
                    break;
                }
                buffer.append(c);
            }
            return buffer.toString();
        }
        
        public static void replaceSpaces(char[] str, int length) {
            int spaceCount = 0;
            int index = 0; 
            int i = 0;
            for (i = 0; i < length; i++) {
                if (str[i] == ' ') {
                    spaceCount++;
                }
            }
            index = length + spaceCount * 2;
            str[index] = '';
            for (i = length - 1; i >= 0; i--) {
                if (str[i] == ' ') {
                    str[index - 1] = '0';
                    str[index - 2] = '2';
                    str[index - 3] = '%';
                    index = index - 3;
                } else {
                    str[index - 1] = str[i];
                    index--;
                }
            }
        }
    
    }
    View Code

    注意:处理字符串操作问题时,常见做法是从字符串尾部开始编辑,从后往前反向操作。因为字符串尾部有额外的缓冲,可以直接修改,不必担心会复写原有数据。

    5.利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变成a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。

    public class StringZipper {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String str = "aabccccaaa";
            System.out.println(compressString(str));
        }
        
        public static String compressString(String str) {
            if (str.length() == 0) {
                return str;
            }
            int flag = 0;
            int count = 1;
            StringBuffer sb = new StringBuffer();
            char last = str.charAt(0);
            for (int i = 1; i < str.length(); i++) {
                if (str.charAt(i) == last) {
                    count++;
                    flag = 1;
                } else {
                    sb.append(last);
                    sb.append(count);
                    last = str.charAt(i);
                    count = 1;
                }
            }
            sb.append(last);
            sb.append(count);
            if (flag == 0 || sb.length() >= str.length()) {
                return str;
            } else {
                return sb.toString();
            }
        }
        
    }
    View Code

    注意:使用flag变量记录字符串中是否有重复字符。若最终flag=0说明字符串中无重复字符,返回原字符串。时间复杂度和空间复杂度都为o(N)。

    6.给定一幅由N*N矩阵表示的图像,其中每个像素的大小为4字节,编写一个方法,将图像旋转90度。不占用额外内存空间能否做到?

    二维数组a[n][n]顺时针旋转90度,找规律如下:

    当n=1时,不动。当n=2时,有:a[0][0] = a[1][0]  a[1][0] = a[1][1]  a[1][1] = a[0][1]  a[0][1] = a[0][0]  初步总结规律为:a[i][j] = a[n-1-j][i]

    当n=3,4,5,……时也是满足的。到这里,如果不考虑空间复杂度,只需要再构建一个二维数组b[n][n],利用公式b[i][j] = a[n-1-j][i]就可以解决。代码如下:

    public void rotate(int[][] matrix) {
    
            int n = matrix.length;
    
            int[][] m = new int[n][n];
    
            for(int row=0;row<n;row++){
    
                for(int col=0;col<n;col++){
    
                    m[row][col] = matrix[n-1-col][row];
    
                }
    
            }
    
            //再赋值回matrix,注意java是形参是引用传递
    
            for(int row=0;row<n;row++){
    
                for(int col=0;col<n;col++){
    
                    matrix[row][col] = m[row][col];
    
                }
    
            }
    
     }
    View Code

    但是题目要求不占用额外空间,应该怎么旋转?接着上面的分析,以n=3为例:把焦点放在一个元素的旋转上,可以看出要在原数组中旋转,在不丢失数据的情况下,每个值的旋转会“波及”4个数,以1为例波及到了1,3,7,9,每个数旋转要不丢失数据就要考虑如何让这4个数都得以保留。前边总结了规律a[i][j] = a[n-1-j][i],分析每组被波及的数,我们可以得出这里波及了的4个数其实就是a[i][j]  a[n-1-j][i]  a[n-1-i][n-1-j]  a[n-1-(n-1-j)][n-1-i]=a[j][n-1-i] 所以这里需要引入一个临时变量temp就可以解决这4个数的顺时针交换,如:

     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;

    把焦点放在一个元素上,数交换的问题解决了。那么现在把焦点回到整个二维数组上来,每个数的旋转会波及4个数,相当于用上面的方法,每旋转一个数,就把一组的4个数都旋转了,

    所以现在的问题就是如何才能完整的把所有的数都旋转90度且不会多旋转,继续分析:

    n=1时,不需旋转。

    n=2时,只需要完成1(a[0][0])的旋转,就完成了整个数组的旋转。

    n=3时,需要完成1,2(a[0][0],a[0][1])的旋转,就完成了整个数组的旋转。

    n=4时,需要完成1,2,3,6(a[0][0至3],a[1][1])的旋转。

    n=5时,需要完成(a[0][0至4],a[1][1至2])的旋转。

    大致可以总结出这么一个规律:对于要旋转的数a[i][j]满足,i<n/2 且 i<=j<n-1-i,至此问题终于解决。

    public class Rotate {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            int[][] arr = {{1,2,3}, {4,5,6}, {7,8,9}};
            int length = arr.length;
            int[][] arr1 = transform(arr, length);
            for(int i = 0; i < length; ++i) {
                  for(int j = 0; j < length; ++j) {
                     System.out.print(arr1[i][j]+" ");
                  }
            }
    
        }
        
        public static int[][] transform(int[][]matrix, int n) {
            int limit = n / 2;
            for (int i = 0; i < limit; i++) {
                for(int j = i; j < n - i - 1; 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;
                }
            }
            return matrix;
        }
    
    }
    View Code

    算法的时间复杂度为o(N的平方),已经是最优做法。

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

    public class ClearZeros {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            int[][] arr = {{1,2,0}, {4,5,6}, {7,8,9}};
            int[][] arr1 = setZeros(arr);
            for(int i = 0; i < arr.length; ++i) {
                  for(int j = 0; j < arr[0].length; ++j) {
                     System.out.print(arr1[i][j]+" ");
                  }
            }
        }
        
        public static int[][] setZeros(int[][] matrix) {
            boolean[] row = new boolean[matrix.length];
            boolean[] column = new boolean[matrix[0].length];
            for (int i = 0; i < matrix.length; i++) {
                for (int j = 0; j < matrix[0].length; j++) {
                    if (matrix[i][j] == 0) {
                        row[i] = true;
                        column[j] = true;
                    }
                }
            }
            for (int i = 0; i < matrix.length; i++) {
                for (int j = 0; j < matrix[0].length; j++) {
                    if (row[i] || column[j]) {
                        matrix[i][j] = 0;
                    }
                }
            }
            return matrix;
        }
    
    }
    View Code

    注意:不能在第一次遍历整个矩阵时,发现值为零的元素就直接将其所在的行与列清零,这样的话最后整个矩阵的所有元素都会变为零。要新建一个矩阵标记零元素的位置,在第二次遍历矩阵时将零元素所在的行与列清零。而且只需记录哪行和哪列有零元素即可,无须记录零元素的确切位置。

    8.假定有一个方法isSubstring,可检查一个单词是否为其他字符串的子串。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成,要求只能调用一次isSubstring。(比如,waterbottle是erbottlewat旋转后的字符串)。

    public class IsRotation {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            System.out.println(isRotation("abc","abc"));
        }
        
        public static boolean isSubstring(String str1,String str2){
            if(str1.contains(str2) || str2.contains(str1)) {
                return true;
            }
            return false;
        }
        public static boolean isRotation(String str1,String str2){
            if(str1.length() != str2.length()) {
                return false;
            }
            String sum = str1 + str1;
            return isSubstring(sum, str2);
        }
    
    }
    View Code

    注意:假定s2由s1旋转而成,那么将s1切分成x和y,就会满足xy=s1和yx=s2。不论x和y之间的分割点在哪,yx都肯定是xyxy的子串,也即s2总是s1s1的子串。直接调用isSubstring(s1s1,s2)即可。

  • 相关阅读:
    LVS基于DR模式负载均衡的配置
    Linux源码安装mysql 5.6.12 (cmake编译)
    HOSt ip is not allowed to connect to this MySql server
    zoj 3229 Shoot the Bullet(无源汇上下界最大流)
    hdu 3987 Harry Potter and the Forbidden Forest 求割边最少的最小割
    poj 2391 Ombrophobic Bovines(最大流+floyd+二分)
    URAL 1430 Crime and Punishment
    hdu 2048 神、上帝以及老天爷(错排)
    hdu 3367 Pseudoforest(最大生成树)
    FOJ 1683 纪念SlingShot(矩阵快速幂)
  • 原文地址:https://www.cnblogs.com/struggleli/p/7815584.html
Copyright © 2011-2022 走看看