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)即可。

  • 相关阅读:
    求得分除以总分的百分比
    考试用时存入秒数,最后用方法转换一成这种格式 (00:00:00)
    微信生成二维码 只需一个网址即刻 还有jquery生成二维码
    微信公众号整套逻辑的支付和退款
    thinkphp 无限极 评论
    新版谷歌浏览器怎么查找和改变编码格式 IT开发人员谷歌的编码格式
    【bzoj2199】[Usaco2011 Jan] 奶牛议会
    BZOJ1997 [Hnoi2010]Planar (2-sat)
    uvalive 3211 Now or later
    codeforce 660D Number of Parallelograms
  • 原文地址:https://www.cnblogs.com/struggleli/p/7815584.html
Copyright © 2011-2022 走看看