剑指offer题解14
26 字符串的排列
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
分析:字典生成算法
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> res=new ArrayList<>();
if(str==null||str.length()==0){
return res;
}
char[] arr=str.toCharArray();
help(arr,0,res);
//返回的结果不是按照字典排序,因此需要手动排序
Collections.sort(res);
return res;
}
private void help(char[] arr,int st,ArrayList<String> res){
if(st==arr.length-1){
res.add(new String(arr));
}else{
for(int i=st;i<arr.length;i++){
//去重,如果两个元素相等,就不必交换了,因为交换了结果也一样
if(i==st||arr[i]!=arr[st]){
swap(arr,st,i);
help(arr,st+1,res);
swap(arr,st,i);
}
}
}
}
private void swap(char[] arr,int i,int j){
char temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
27 数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
分析:由于该数的次数超过的半数,那么遇见此数就+1,反之就-1,得到最后存在的数,然后再遍历数组计算该数的次数。
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
int res=0,count=0;
for(int i=0;i<array.length;i++){
if(array[i]==res){
count++;
}else if(count--==0){
res=array[i];
count=1;
}
}
count=0;
for(int i=0;i<array.length;i++){
if(array[i]==res){
count++;
}
if(count>array.length/2){
return res;
}
}
return 0;
}
}
//直接计数
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
Map<Integer,Integer> count=new HashMap<>();
for(int num:array){
count.put(num,count.getOrDefault(num,0)+1);
if(count.get(num)>array.length/2){
return num;
}
}
return 0;
}
}
28 最小的k个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
分析:
方法一:直接排序
方法二:使用一个大顶堆,如果新出现的数字比对堆顶的数小,就弹出堆顶,将其放入堆中
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> res=new ArrayList<>();
if(k>input.length){
return res;
}
Arrays.sort(input);
for(int i=0;i<k;i++){
res.add(input[i]);
}
return res;
}
}
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> res=new ArrayList<>();
if(k>input.length||k==0){
return res;
}
//建堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
public int compare(Integer a,Integer b){
return b-a;
}
});
for(int i=0;i<input.length;i++){
if(maxHeap.size()!=k){
maxHeap.offer(input[i]);
}else if(maxHeap.peek()>input[i]){
maxHeap.poll();
maxHeap.offer(input[i]);
}
}
for(int a:maxHeap){
res.add(a);
}
return res;
}
}
29 连续子数组的最大和
题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
分析:动态规划,如果之前的 sum+array[i]< array[i] ,那么肯定的应该更新sum=array[i],并且应该记住当前最大的值
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int res=array[0],max=array[0];
for(int i=1;i<array.length;i++){
max=Math.max(array[i],max+array[i]);
res=Math.max(res,max);
}
return res;
}
}