主元素(数组中出现次数超过一半的数字)

数组中的逆序对

第一个只出现一次的字符位置

把数组排成最小的数

整数中1出现的次数

连续子数组的最大和

字符串的全排列

扑克牌顺子

顺时针打印矩阵

调整数组顺序使奇数位于偶数前面

最小的K个数

数组中只出现一次的数字

数字在排序数组中出现的次数

数组中重复的数字

构建乘积数组

正则表达式匹配

矩阵中的路径

 

矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵(3*4)中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

/**
 回溯法
 用一个状态数组保存之前访问过的字符,然后再分别按上,下,左,右递归
*/
public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
        int flag[] = new int[matrix.length];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (helper(matrix, rows, cols, i, j, str, 0, flag))
                    return true;
            }
        }
        return false;
    }
 
    private boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag) {
        int index = i * cols + j;
        if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == 1)
            return false;
        if(k == str.length - 1) return true;
        flag[index] = 1;
        if (helper(matrix, rows, cols, i - 1, j, str, k + 1, flag)
                || helper(matrix, rows, cols, i + 1, j, str, k + 1, flag)
                || helper(matrix, rows, cols, i, j - 1, str, k + 1, flag)
                || helper(matrix, rows, cols, i, j + 1, str, k + 1, flag)) {
            return true;
        }
        flag[index] = 0;
        return false;
    }
}

 

 

正则表达式匹配

 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 

在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。

/*
当模式中的第二个字符不是“*”时:
1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。
2、如果 字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。

而当模式中的第二个字符是“*”时:
如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式:
1、模式后移2字符,相当于x*被忽略;
2、字符串后移1字符,模式后移2字符;
3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;
*/
public class Solution {
    public boolean match(char[] str, char[] pattern) {
    if (str == null || pattern == null) {
        return false;
    }
    int strIndex = 0;
    int patternIndex = 0;
    return matchCore(str, strIndex, pattern, patternIndex);
}
  
    public boolean matchCore(char[] str, int strIndex, char[] pattern, int patternIndex) {
        //有效性检验:str到尾,pattern到尾,匹配成功
        if (strIndex == str.length && patternIndex == pattern.length) {
            return true;
        }
        //pattern先到尾,匹配失败
        if (strIndex != str.length && patternIndex == pattern.length) {
            return false;
        }
        //模式第2个是*,且字符串第1个跟模式第1个匹配,分3种匹配模式;如不匹配,模式后移2位
        if (patternIndex + 1 < pattern.length && pattern[patternIndex + 1] == '*') {
            if ((strIndex != str.length && pattern[patternIndex] == str[strIndex]) || (pattern[patternIndex] == '.' && strIndex != str.length)) {
                return matchCore(str, strIndex, pattern, patternIndex + 2)//模式后移2,视为x*匹配0个字符
                    || matchCore(str, strIndex + 1, pattern, patternIndex + 2)//视为模式匹配1个字符
                    || matchCore(str, strIndex + 1, pattern, patternIndex);//*匹配1个,再匹配str中的下一个
            } else {
                return matchCore(str, strIndex, pattern, patternIndex + 2);
            }
        }
        //模式第2个不是*,且字符串第1个跟模式第1个匹配,则都后移1位,否则直接返回false
        if ((strIndex != str.length && pattern[patternIndex] == str[strIndex]) || (pattern[patternIndex] == '.' && strIndex != str.length)) {
            return matchCore(str, strIndex + 1, pattern, patternIndex + 1);
        }
        return false;
    }
}

 

 

 

构建乘积数组

给定一个数组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]。不能使用除法。

/* 设 n=5
对于第一个for循环
第一步:b[0] = 1;
第二步:b[1] = b[0] * a[0] = a[0]
第三步:b[2] = b[1] * a[1] = a[0] * a[1];
第四步:b[3] = b[2] * a[2] = a[0] * a[1] * a[2];
第五步:b[4] = b[3] * a[3] = a[0] * a[1] * a[2] * a[3];
然后对于第二个for循环
第一步
b[4] = b[4]*tmp = a[0] * a[1] * a[2] * a[3];
第一步
temp *= a[4] = a[4]; 
b[3] = b[3] * temp = a[0] * a[1] * a[2] * a[4];
第二步
temp *= a[3] = a[4] * a[3];
b[2] = b[2] * temp = a[0] * a[1] * a[4] * a[3];
第三步
temp *= a[2] = a[4] * a[3] * a[2]; 
b[1] = b[1] * temp = a[0] * a[4] * a[3] * a[2];
第四步
temp *= a[1] = a[4] * a[3] * a[2] * a[1]; 
b[0] = b[0] * temp = a[4] * a[3] * a[2] * a[1];
由此可以看出从b[4]到b[0]均已经得到正确计算。
*/
public class Solution {
    public int[] multiply(int[] A) {
        int len = A.length;
        int[] B = new int[len];
        B[0] = 1;
        for(int i=1; i<len; i++){
            B[i] = B[i-1] * A[i-1];
        }
        int tmp = 1;
        for(int i=len-1; i>=0; i--){
            B[i] = B[i] * tmp;
            tmp = tmp * A[i];
        }
        return B;
    }
}

 

 

 

数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。
请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。

public class Solution {
    //找出任意重复的一个,赋值duplication[0]
    // Return value: true if the input is valid, and there are some duplications in the array number otherwise false
    
    /**
      (一)、从头扫到尾,只要当前元素值与下标不同,就做一次判断,numbers[i]与numbers[numbers[i]],相等就认为找到了
      重复元素,返回true,否则就交换两者,继续循环。直到最后还没找到认为没找到重复元素,返回false
    */    
    public boolean duplicate(int numbers[],int length,int [] duplication){
        for(int i=0; i<length; i++){
            while(i!=numbers[i]){
                if(numbers[i] == numbers[numbers[i]]){
                    duplication[0] = numbers[i];
                    return true;
                }
                int tmp = numbers[i];
                numbers[i] = numbers[tmp];
                numbers[tmp] = tmp;
            }
        }
        return false;
    }
    
    // (二)
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        StringBuffer sb = new StringBuffer();  
        for(int i = 0; i < length; i++){
                sb.append(numbers[i] + "");
        }
        for(int j = 0; j < length; j++){
            if(sb.indexOf(numbers[j]+"") != sb.lastIndexOf(numbers[j]+"")){
                duplication[0] = numbers[j];
                return true;
            }
        }
        return false;
    }
    
    // (三)
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        for(int i=0; i<length; i++){
            int index = numbers[i];
            if(index>=length){
                index -= length;
            }
            if(numbers[index]>=length){
                duplication[0] = index;
                return true;
            }
            numbers[index] = numbers[index]+length;
        }
        return false;
    }
}

 

 

 

数字在排序数组中出现的次数

在一个排序数组中,找出给定数字出现的次数。

// 二分查找 找到第一个K 和 最后一个K, 二者位置相减
public class Solution{
    public int getNumOfK(int[] arr, int k){
        int number = 0;
        int first = getFirstIndex(arr, k, 0, arr.length-1);
        int last = getLastIndex(arr, k, 0, arr.length-1);
        if(first > -1 && last > -1){
            number = last - first + 1;
        }
        return number;
    }
    // 找到第一个k
    private int getFirstIndex(int[] arr, int k, int start, int end){
        if(start>end){
            return -1;
        }
        int mid = (start+end)/2;
        if(arr[mid] == k){
            if((mid>0 && arr[mid-1]!=k) || mid==0){
                return mid;
            }else{
                end = mid - 1;
            }
        }else{
            if(mid > k){
                end = mid - 1;
            }else{
                start = mid + 1;
            }
        }
        return getFirstIndex(arr, k, start, end);
    }
    // 找到最后一个k
    private int getLastIndex(int[] arr, int k, int start, int end){
        if(start>end){
            return -1;
        }
        int mid = (start+end)/2;
        if(arr[mid] == k){
            if((mid<end && arr[mid+1]!=k) || mid==end){
                return mid;
            }else{
                start = mid + 1;
            }
        }else{
            if(mid > k){
                end = mid - 1;
            }else{
                start = mid + 1;
            }
        }
        return getLastIndex(arr, k, start, end);
    }
}

 

 

数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

// num1,num2分别为长度为1的数组。传出参数将num1[0],num2[0]设置为返回结果
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
    ArrayList<Integer> list = new ArrayList<>();
    for(int i=0; i<array.length; i++){
        if(!list.contains(array[i])){
            list.add(array[i]);
        }else{
            list.remove(new Integer(array[i]));
        }
    }
    if(list.size()>1){
        num1[0] = list.get(0);
        num2[0] = list.get(1);
    }
}

 

 

 

最小的K个数

 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4

public ArrayList<Integer> getLeastNumbers(int[] input, int k){
    if(input==null)
        return null;
    
    ArrayList<Integer> list = new ArrayList<>();
    if(k > input.length){
        return list;
    }
    
    for(int i=0; i<k; i++){
        for(int j=i+1; j<input.length; j++){
            if(input[i]>input[j]){
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
        list.add(input[i]);
    }
    return list;
}

 

 

调整数组顺序使奇数位于偶数前面

//1. 保证奇数和奇数,偶数和偶数之间的相对位置不变。
public void partitionArray(int[] arr){
    int len = arr.length;
    for(int i=1; i<len; i++){
        if(arr[i]%2!=0){
            for(int j=i; j>0; j--){
                if(arr[j-1]%2==0){
                    int t = arr[j];
                    arr[j] = arr[j-1];
                    arr[j-1] = t;
                }
            }
        }
    }
}

//2. 不用保证奇数和奇数,偶数和偶数之间的相对位置不变。
public void partitionArray(int[] arr){
    int left = 0;
    int right = arr.length-1;
    
    while(left<right){
        while(arr[left]%2!=0 && left<right){
            left++;
        }
        while(arr[rigth]%2==0 && left<right){
            right--;
        }
        if(left<right){
            int tmp = arr[left];
            arr[left] = arr[right];
            arr[right] = tmp;
            left++;
            right--;
        }
    }
}

 

 

顺时针打印矩阵

 必须先得到层数。对于m行n列,layer=(Math.min(m, n)-1)/2+1;

public ArrayList<Integer> printMatrix(int[][] matrix){
    ArrayList<Integer> list = new ArrayList<>();
    if(matrix.length==0){
        return list;
    }
    
    int m = matrix.length;
    int n = matrix[0].length;
    int layer = (Math.min(m,n)-1)/2+1;
    for(int i=0; i<layer; i++){
        // leftTop-->rightTop
        for(int a=i; a<n-i; a++){
            list.add(matrix[i][a]);
        }
        // rightTop-->rightDown
        for(int b=i+1; b<m-i; b++){
            list.add(matrix[b][n-1-i]);
        }
        // rightDown-->leftDown
        for(int c=n-1-i-1; (c>=i)&&(m-1-i)!=i; c--){
            list.add(matrix[m-1-i][c]);
        }
        // leftDown-->leftTop
        for(int d=m-1-i-1; (d>i)&&(n-1-i)!=i; d--){
            list.add(matrix[d][i]);
        }
    }
    
    return list;
}

 

 

扑克牌顺子

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...
他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”
不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。
上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。
现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。

即:输入一个数组,包含5个从0-13的数,0可以当作任何数,判断这5个数是不是连续的。

// 一:排序-->统计0的个数-->统计需要0的个数-->比较
public boolean isContinuous(int[] nums){
    if(nums==null || nums.length!=5){
        return false;
    }
    Arrays.sort(nums);
    int cnt0 = 0;
    int cntNeed = 0;
    for(int i=0; i<nums.length; i++){
        if(nums[i]==0){
            cnt0++;
        }else{
            if(i<4){
                if(nums[i+1]==nums[i]){
                    return false;
                }
                cntNeed += nums[i+1]-nums[i]-1;
            }
        }
    }
    if(cntNeed > cnt0){
        return false;
    }
    return true;
}
// 二:必须满足两个条件:1.除0外没有重复数;2.max-min<5”
public boolean isContinuous(int[] nums){
    if(nums==null || nums.length!=5){
        return false;
    }
    Arrays.sort(nums);
    int cnt0 = 0;
    for(int i=0; i<nums.length; i++){
        if(nums[i]==0){
            cnt0++;
        }else{
            if(i<4 && (nums[i+1]==nums[i])){
                return false;
            }
        }
    }
    if(cnt0>=4){
        return true;
    }
    if((nums[nums.length-1]-nums[cnt0])<5){
        return true;
    }
    return false;
}

 

 

字符串的全排列

 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。

public ArrayList<String> Permutation(String str) {
    ArrayList<String> re = new ArrayList<String>();
    if (str == null || str.length() == 0) {
        return re;
    }
    TreeSet<String> set = new TreeSet<String>();
    fun(set, str.toCharArray(), 0);
    re.addAll(set);
    return re;
}

private void fun(TreeSet<String> re, char[] str, int k) {
    if (k == str.length) {
        re.add(new String(str));
        return;
    }
    for (int i = k; i < str.length; i++) {
        swap(str, i, k);
        fun(re, str, k + 1);
        swap(str, i, k);
    }
}
private void swap(char[] str, int i, int j) {
    if (i != j) {
        char t = str[i];
        str[i] = str[j];
        str[j] = t;
    }
}

 

 

连续子数组的最大和

public int maxSumOfSubarray(int[] array){
    if(arr==null || array.length==0){
        return 0;
    }
    int maxEndingHere = array[0];
    int maxSoFar = array[0];
    for(int i=0; i<array.length; ++i){
        maxEndingHere = Math.max(array[i], maxEndingHere+array[i]);
        maxSoFar = Math.max(maxSoFar, maxEndingHere);
    }
    return maxSoFar;
}

 

整数中1出现的次数

 从1到n的整数中1出现的次数(1~13中包含1的数字有1、10、11、12、13因此共出现6次)

public int numOfOne(int n){
    if(n<1){
        return 0;
    }
    if(n<=9){
        return 1;
    }
    
    int count = 1;
    for(int i=10; i<n; ++i){
        int j = i;
        while(j/10!=0){ // j>=10
            if(j%10==1){ // 各位数为1
                count++;
            }
            if(j<20){
                count++;
            }
            j /= 10;
        }
    }
    return count;
}

 

 

把数组排成最小的数

 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

分析:四步:int[] --> String[] --> sort --> joint

public class Solution {
    public String PrintMinNumber(int [] numbers) {
        if(numbers==null || numbers.length==0)
            return "";
        
        String[] strArray = new String[numbers.length];
        StringBuffer sb = new StringBuffer();
        for(int i=0; i<strArray.length; i++){
            strArray[i] = String.valueOf(numbers[i]);
        }
        
        Arrays.sort(strArray, new Comparator<String>(){
            public int compare(String s1, String s2){
                String c1 = s1+s2;
                String c2 = s2+s1;
                return c1.compareTo(c2);
            }
        });
        
        for(int i=0; i<strArray.length; i++){
            sb.append(strArray[i]);
        }
        
        return sb.toString();
    }
}

 

 

第一个只出现一次的字符位置

在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符的位置。若为空串,返回-1。位置索引从0开始.

public int firstNotRepeatingChar(String str){
    if(str==null || str.length()==0){
        return -1;
    }
    int[] count = new int[26];
    char c = 'a';
    
    for(int i=0; i<str.length(); ++i){
        count[str.charAt(i)-c]++;
    }
    
    for(int i=0; i<str.length(); ++i){
        if(count[str.charAt(i)-c]==1){
            return i;
        }
    }
    return -1;
}

 


主元素(数组中出现次数超过一半的数字)

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        // 不存在主元素时,就不能用此方法
        /*
        int cur = array[0];
        int count = 0;
        for(int i=0; i<array.length; i++){
            
            if(count==0){
                cur = array[i];
                count = 1;
            }else{
                if(cur==array[i]){
                    count++;
                }else{
                    count--;
                }
            }
        }
        return cur;
        */
        
        HashMap<Integer, Integer> map = new HashMap<>();
        for(int i=0; i<array.length; i++){
            int num = array[i];
            if(map.containsKey(num)){
                map.put(num, map.get(num)+1);
            }else{
                map.put(num, 1);
            }
            if(map.get(num)>array.length/2){
                return num;
            }
        }
        return 0;
        
    }
}

 

数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

分析:利用归并排序思想。

public class Solution {
    // 利用归并排序思想
    public int InversePairs(int[] A) {
        return mergeSort(A, 0, A.length - 1);
    }
    
    private int mergeSort(int[] A, int start, int end) {
        if (start >= end) {
            return 0;
        }
        
        int mid = (start + end) / 2;
        int sum = 0;
        sum += mergeSort(A, start, mid);
        sum += mergeSort(A, mid+1, end);
        sum += merge(A, start, mid, end);
        return sum;
    }
    
    private int merge(int[] A, int start, int mid, int end) {
        int[] temp = new int[A.length];
        int leftIndex = start;
        int rightIndex = mid + 1;
        int index = start;
        int sum = 0;
        
        while (leftIndex <= mid && rightIndex <= end) {
            if (A[leftIndex] <= A[rightIndex]) {
                temp[index++] = A[leftIndex++];
            } else {
                temp[index++] = A[rightIndex++];
                sum += mid - leftIndex + 1;
            }
        }
        while (leftIndex <= mid) {
            temp[index++] = A[leftIndex++];
        }
        while (rightIndex <= end) {
            temp[index++] = A[rightIndex++];
        }
        
        for (int i = start; i <= end; i++) {
            A[i] = temp[i];
        }
        
        return sum;
    }
}