文章目录
- 10.1合并排序的数组
- 10.02变位词组
- 10.03搜索旋转数组
- 10.05稀疏数组搜索
- 10.09排序矩阵查找
- 10.10 数字流的秩
- 10.11 峰与谷
10.1合并排序的数组
这个就从后往前加入到新数组里就行。如果B的下标是-1则结束,A的下标是-1则一直加B的元素。
class Solution {
public:
void merge(vector<int>& A, int m, vector<int>& B, int n) {
int p1 = m - 1, p2 = n - 1;
int tail = m + n - 1;
int cur;
while(p1>=0 ||p2>=0)
{
if(p1==-1)
A[tail--]=B[p2--];
else if(p2==-1)
return;
else
{
if(A[p1]<B[p2])
A[tail--]=B[p2--];
else
A[tail--]=A[p1--];
}
}
}
};
10.02变位词组
用一个大哈希表模拟就行,用Java写的过程中注意各种函数名
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> res=new ArrayList<List<String>>();
Map<String,List<String>> map=new HashMap<>();
for(int i=0;i<strs.length;i++){
char[] arr=strs[i].toCharArray();
Arrays.sort(arr);
String s=new String(arr);
if(!map.containsKey(s)){
List<String> temp=new ArrayList<>();
temp.add(strs[i]);
map.put(s,temp);
}else{
map.get(s).add(strs[i]);
}
}
for(String key:map.keySet()){
res.add(map.get(key));
}
return res;
}
}
1.在右边的所有New,都是new HashMap<>(),这种,有<>也有()的
2.String[] strs是没有size()的,只有length;
3.字符串转换为字符数组,便于后序排序,char[] arr=strs[i].toCharArray();
4.对字符数组排序,并且会改变字符数组。Arrays.sort(arr);
5.在一个HashMap中查找包不包含这个键。map.containsKey(s)
6.在一个HashMap中添加一个元素,map.put(key,value), map.put(s,temp);
7.在一个HashMap中得到一个Key背后的元素。map.get(key);
10.03搜索旋转数组
旋转数组一定是,递增序列,中断,递增序列。
搜索的话,二分,先找到中断值,也就是最小值。
然后假设把左边的移动到右边,具体做法,在arr里面,下标都要对n取余。
class Solution {
public:
int search(vector<int>& arr, int target) {
int n=arr.size();
while(n>1&&arr[n-1]==arr[0]) n--; //让最左边和最右边不相同
//求最小值的索引
int l=0,r=n-1;
while(l<r){
int mid=(l+r)>>1;
if(arr[mid]<=arr[r]) r=mid;
else l=mid+1;
}
//求target的索引
r=l+n-1;
if(target<arr[l]) return -1;
while(l<r){
int mid=(l+r)>>1;
if(arr[mid%n]>=target) r=mid;
else l=mid+1;
}
if(arr[l%n]==target) return l%n;
return -1;
}
};
10.05稀疏数组搜索
有序则二分
class Solution {
public:
int findString(vector<string>& words, string s) {
int l=0,r=words.size()-1;
while(l<=r)
{
int mid=l+r>>1;
// 遇到空字符串时,mid右移,直到遇到非空字符串为止
while(mid>l&&words[mid].empty())mid++;
if(words[mid]==s)return mid;
else if(words[mid]>s)r=mid-1;
else l=mid+1;
}
return -1;
}
};
10.09排序矩阵查找
从右上角开始寻找。通过比较决定向下走还是向左走。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0) {
return false;
}
int m = matrix.length, n = matrix[0].length, row = 0, col = n - 1;
while (row < m && col >= 0) {
if (matrix[row][col] < target) {
row++;
} else if(matrix[row][col] > target) {
col--;
} else {
return true;
}
}
return false;
}
}
10.10 数字流的秩
树状数组可以高效的计算前缀和,其查询前缀和点更新(修改)都可以在O(logN)时间内完成
计算c[i]对应的区间长度,要用到Lowbit,即求一个数的最后一个非0的位置
lowbit(10100)=00100
int lowbit(int i) { return i & (-i); }
查询前缀和,去把所有的前缀c[i]的值都加上。而c[i]的直接前驱为c[i-lowbit(i)]
int sum(int i){
int s=0;
for(;i>0;i-=lowbit(i)) s+=c[i];
return s;}
点更新,要对所有后缀c[i]进行修改,而c[i]的直接后缀为c[i+lowbit(i)]
void add(int i,int z){
for(;i<n;i+=lowbit(i)) c[i]+=z; }
注意:树状数组下标从1开始,因为lowbit(0)=0会出现死循环
查询区间和,求a[i]+…+a[j],则用sum(j)-sum(i-1)
int sum(int i,int j){ return sum(j)-sum(i-1); }
代码如下:
class StreamRank {
public int lowbit(int i) { return i & (-i); }
public int sum(int j){
int s=0;
for(int i=j;i>0;i-=lowbit(i)) s+=c[i];
return s;
}
public void add(int j,int z){
for(int i=j;i<n;i+=lowbit(i)) c[i]+=z;
}
public int sum(int i,int j){ return sum(j)-sum(i-1); }
private int[] c;
private int n=50002;
public StreamRank() {
c=new int [n+1];
}
public void track(int x) {
add(x+1,1);
}
public int getRankOfNumber(int x) {
return sum(x+1);
}
}
前面四个函数是固定的,sum有一个参数的(前缀和),也有俩参数的(区间和)
为什么要用x+1,因为x的值可能为0,这样会死循环,所以统一加一。.
10.11 峰与谷
这个题没意思,可以直接排序。贪心也很简单。