1、数组中重复的数字
题目描述
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
Input:
{2, 3, 1, 0, 2, 5}
Output:
2
解题思路
1)任意一个重复的数字,所以当查找到第一个重复的时候就可以return
2)如果要求时间复杂度O(N),空间复杂度O(1)。则不能使用排序算法。如果没有要求,可以先进行排序,扫描排序之后的数组即可。
3)解决思路一:采用将值为i的元素调整到第i个位置,如果发现位置上面的元素已经有对应数值了,则发现有重复。先进行交换,将所有数字放入对应的位置,交换前面加上一个判断,如果你发现对应位置的数字是对的,然后你又发现一个这样的数字,那这个数字就是重复的一个数字。如果发现多个,那将重复的数字放在数组中进行保存。
解决思路二:哈希表。从头到尾扫描数组,每扫描到一个数字,判断该数字是否在哈希表中,如果该哈希表还没有这个数字,那么加入哈希表,如果已经存在,则返回该数字;时间复杂度:O(n),空间复杂度:O(n)
解决思路三:排序,再遍历
交换数字,按位置比较。
- public class repeatNum3 {
- /**
- * @param ycy
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- int[] num= {2,3,1,0,2,5};
- int repeat = 0;
- int j = 0;
- if(num == null || num.length<=0){
- System.out.println("不存在重复的数据");
- }
- System.out.println("数据长度"+num.length);
- for(int i=0;i<num.length;i++){
- while(num[i] != i){
- if(num[i] == num[num[i]]){
- repeat = num[i];
- System.out.println("存在重复的数据"+repeat);
- return;
- }
- swap(num,i,num[i]);
- }
- }
- return;
- }
- public static void swap(int[] num,int i,int j){
- int t = num[i];
- num[i] = num[j];
- num[j] = t;
- }
- }
各种排序算法比较
各种常用排序算法 | ||||||||
类别 |
排序方法 |
时间复杂度 |
空间复杂度 |
稳定性 |
复杂性 |
特点 | ||
最好 |
平均 |
最坏 |
辅助存储 |
|
简单 |
| ||
插入 排序 |
直接插入 |
O(N) |
O(N2) |
O(N2) |
O(1) |
稳定 |
简单 |
|
希尔排序 |
O(N) |
O(N1.3) |
O(N2) |
O(1) |
不稳定 |
复杂 |
| |
选择 排序 |
直接选择 |
O(N) |
O(N2) |
O(N2) |
O(1) |
不稳定 |
|
|
堆排序 |
O(N*log2N) |
O(N*log2N) |
O(N*log2N) |
O(1) |
不稳定 |
复杂 |
| |
交换 排序 |
冒泡排序 |
O(N) |
O(N2) |
O(N2) |
O(1) |
稳定 |
简单 |
1、冒泡排序是一种用时间换空间的排序方法,n小时好 |
快速排序 |
O(N*log2N) |
O(N*log2N) |
O(N2) |
O(log2n)~O(n) |
不稳定 |
复杂 |
1、n大时好,快速排序比较占用内存,内存随n的增大而增大,但却是效率高不稳定的排序算法。 | |
归并排序 |
O(N*log2N) |
O(N*log2N) |
O(N*log2N) |
O(n) |
稳定 |
复杂 |
1、n大时好,归并比较占用内存,内存随n的增大而增大,但却是效率高且稳定的排序算法。 | |
基数排序 |
O(d(r+n)) |
O(d(r+n)) |
O(d(r+n)) |
O(rd+n) |
稳定 |
复杂 |
| |
注:r代表关键字基数,d代表长度,n代表关键字个数 |
2、二维数组中的查找
题目描述
给定一个二维数组,其每一行从左到右递增排序,从上到下也是递增排序。给定一个数,判断这个数是否在该二维数组中。
Consider the following matrix:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
Given target = 5, return true.
Given target = 20, return false.
解题思路
1 )二维数组是一个有序数组,其任意一个数是大于他左边的数,小于其下边的数。所以可以从右上角进行比较,然后根据target与当前元素的大小关系进行对应的位置范围缩小。
2 )如果等于当前比较元素则直接进行返回,如果大于当前元素则下移一行,如果小于小于当前元素,则左移一列。
剑指offer通过的代码:
- public class Solution {
- public boolean Find(int target, int [][] array) {
- boolean result = false;
- System.out.println(" "+array.length+" "+array[0].length);
- if(array.length==0 || array[0].length==0 )
- return result;
- int i=array.length-1,j=0;
- while(j<array[0].length-1 && i>0)
- {
- if(target>array[i][j])
- j++;
- if(target<array[i][j])
- i--;
- if(target == array[i][j])
- return true;
- }
- return false;
- }
- }
本地编码:
- public class SearchNum4 {
- /**
- * @param ycy
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- int[][] matrix = {{1, 4, 7, 11, 15},{2, 5, 8, 12, 19},{3, 6, 9, 16, 22},{10, 13, 14, 17, 24},{18, 21, 23, 26, 30}};
- int target1 = 5;
- int target2 = 19;
- if(matrix == null || matrix.length == 0|| matrix[0].length == 0){
- System.out.print("二维数组无数据");
- }else{
- int row = matrix.length,cols = matrix[0].length;
- int i = 0,j = cols-1; //右上角的位置
- while(i<= row -1 && j>= 0){
- if(target2 == matrix[i][j]){
- System.out.println("存在");
- return;
- }else if(target2 > matrix[i][j] ){
- i++;
- }else{
- j--;
- }
- }
- System.out.println("不存在");
- }
- return;
- }
- }
3 、替换空格
题目描述
将一个字符串中的空格替换成 "%20"。
Input:
"A B"
Output:
"A%20B"
解题思路
1)将字符串通过 A=input.toCharArray(); 转换为字符数组,如果非空格则直接进行字符相加,如果是空格,则加“%20”。最终得到新的字符串,原来的字符数组长度没有变化,只是产生一个转换后的字符串;
2)因为空格要替换为三个字符%20,所以遍历到空格的时候,在尾部填充两个空格,然后原来的末尾元素填充到新的末尾,然后前面空格部分逆向填充%20;
剑指offer通过的代码为:
- public class Solution {
- public String replaceSpace(StringBuffer str) {
- StringBuffer result = new StringBuffer();
- for(int i=0;i<str.length();i++)
- {
- if(str.charAt(i) == ' ')
- result = result.append( "%20");
- else
- result = result.append(str.charAt(i));
- }
- return result.toString();
- }
- }
解决思路一:字符串转换为字符数组,赋值新字符串的方法
- import java.util.Arrays;
- public class replaceSpace5 {
- /**
- * @param ycy
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- String input = "A B B ";
- String replace = "%20";
- String newString = "";
- char[] A;
- A=input.toCharArray(); //将字符串转换为字符数组
- for(int i=0;i<A.length;i++){
- //System.out.println(input.charAt(i));
- if(' '== A[i]){
- A[i] = '%';
- newString = newString + "%20";
- System.out.println("当前字符串: "+newString);
- }else{
- newString = newString+A[i];
- }
- }
- System.out.println("最终字符串: "+newString);
- System.out.print("A字符串:");
- for(int i=0;i<A.length;i++){
- System.out.print(A[i]);
- }
- return;
- }
- }
解决思路二:扩充字符长度,逆序插入
将String转换成StringBuffer
方式一:利用构造函数
String str=“Hello World.”;
StringBuffer buffer = new StringBuffer(str);
方式二:调用append函数
String str=“Hello World.”;
StringBuffer buffer = new StringBuffer();
buffer.append(str);
实现代码:
public class replaceSpace53 {
/**
* @param ycy
*/
public static String replace(StringBuffer sbf){
int p1 = sbf.length()-1;
for(int i=0;i<=p1;i++){ //此处是i<=p1,不是i<p1,这个要注意
if(sbf.charAt(i)==' '){
sbf.append(" ");
}
}
int p2 = sbf.length()-1;
while(p1>=0 && p2>p1){
char c = sbf.charAt(p1--);
if(c==' '){ //倒叙插入
sbf.setCharAt(p2--, '0');
sbf.setCharAt(p2--, '2');
sbf.setCharAt(p2--, '%');
}else{
sbf.setCharAt(p2--, c);
}
}
return sbf.toString();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String input = "A B B ";
String replace = "%20";
StringBuffer sb = new StringBuffer(input); //将String转换成StringBuffer
String newString = replace(sb);
System.out.print(newString);
}
}
1)String
String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final。
2) StringBuffer的常用方法解析
StringBuffer a=new StringBuffer()
1 public StringBuffer append(String s);
将指定的字符串追加到此字符序列。
2 public StringBuffer reverse()
将此字符序列用其反转形式取代。
3 public insert(int offset, int i)
将 int 参数的字符串表示形式插入此序列中。
4 replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。
3)三者的区别
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况,非线程安全
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况,线程安全的
对于StringBuffer转化为String可使用 String b=a.toString(),对于String转为StringBuffer可使用StringBuffer b=new StringBuffer(string)
扫码关注一起随时随地学习!!!就在洋葱攻城狮,更多精彩,等你来!!