class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> IList=new ArrayList<List<Integer>>();
if(k>n)return IList;
int[] match=new int[n+1];
match[0]=1;
int i;
for(i=1;i<=n;i++)
match[i]=0;
List<Integer> minlist=new ArrayList<Integer>();
circle(IList,n,1,match,k,minlist,0);
return IList;
}
public static void circle(List<List<Integer>> IList,int n,int ii,int[] match,int k,List<Integer> minlist,int size){
int i=ii;
if(k==0&&size==minlist.size()){
IList.add(new ArrayList<>(minlist));//这里是重点
}else{
for(;i<=n;i++){
if(match[i]==0)
{
minlist.add(i);
match[i]=1;
circle(IList,n,i+1,match,k-1,minlist,size+1);
match[i]=0;
minlist.remove(minlist.size()-1);
}
}
}
}
}
初看这题确实挺简单的,思路也清晰,回溯呗。但自己写起代码来真的是毛病多多,虽然看别人代码再来看这题总会有种“不过如此”的感觉。下面说一说我在写这几十行代码出现的一些问题吧。递归函数里面的参数是为了减少时间开销多加的,有些大可不必,说重点,虽然每次生成的minlist里面的数据符合答案,但它貌似没有传进IList,或者说它是以空集的身份传进去的,导致最后return 的结果只有几个空集。也试过用静态变量,但结果一样。在写的时候我一直有个疑问,这个疑问也是导致最后结果错误的根本原因,我只给minlist开辟过一次空间,为什么能多次传入到IList。最后也是在网上查找了解决方法,形参终归是形参啊,最后传入到IList中要新分配空间(虽然有想过这一步,但一直不知道在哪开辟空间合适),将形参拷贝到一个新的空间传入。解决!!!
class Solution {
public List<Integer> countSmaller(int[] nums) {
int n=nums.length;
List<Integer> IList=new ArrayList<Integer>();
if(n==0)return IList;
List<Integer> sort=new ArrayList<Integer>();
int i;
for(i=n-1;i>=0;i--){
int count=0;
for(int j=0;j<sort.size();j++){
if(nums[i]>sort.get(j))
count++;
else
break;
}
IList.add(count);
sort.add(nums[i]);
Collections.sort(sort);
}
sort.clear();
for(i=IList.size()-1;i>=0;i--){
sort.add(IList.get(i));
}
return sort;
}
}
最简单的思路大家都清楚,遍历每个位置,和后面的元素依次比较,统计比当前位置小的个数,时间复杂度为O(n*n)。既然定义为困难,当然不能这么写,所以也是想了些其它办法,从后往前遍历,遍历的同时,将已遍历的元素排序,虽然在下一个元素统计数量的时候会比普通方法快些,但新增的排序时间复杂度貌似也拖了后腿,所以这种方法在最后一个用例超时了。
class Solution {
private int[] index;
private int[] helper;
private int[] count;
public List<Integer> countSmaller(int[] nums) {
List<Integer> res = new ArrayList<>(nums.length);
index = new int[nums.length];
helper = new int[nums.length];
count = new int[nums.length];
for (int i = 0; i < index.length; i++) {
index[i] = i;
}
merge(nums, 0, nums.length - 1);
for (int i = 0; i < count.length; i++) {
res.add(i, count[i]);
}
return res;
}
private void merge(int[] nums, int s, int e) {
if (s == e || s > e) return;
int mid = (s + e) >> 1;
if (s < mid) {
merge(nums, s, mid);
}
if (mid + 1 < e) {
merge(nums, mid + 1, e);
}
int i = s, j = mid + 1;
int hi = s;
while (i <= mid && j <= e) {
if (nums[index[i]] <= nums[index[j]]) {
// 右侧出
helper[hi++] = index[j++];
} else {
// 左侧出 计数
count[index[i]] += e - j + 1;
helper[hi++] = index[i++];
}
}
while (i <= mid) {
//左侧出
helper[hi++] = index[i++];
}
while (j <= e) {
// 右侧出
helper[hi++] = index[j++];
}
for (int k = s; k <= e; k++) {
index[k] = helper[k];
}
}
}
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
int n=intervals.length;
if(intervals.length==0){
int[][] res = new int[1][];
res[0] = newInterval;
return res;
}
int max=intervals[n-1][1]>newInterval[1]?intervals[n-1][1]:newInterval[1];
int min=intervals[0][0]<newInterval[0]?intervals[0][0]:newInterval[0];
int[] str=new int[max+1];
int i;
int match=1;
for(i=0;i<n;i++){
for(int j=intervals[i][0];j<=intervals[i][1];j++)
{
str[j]=match;
}
match++;
}
int temp_match=str[newInterval[1]];
int temp_i=newInterval[1];
while(temp_match!=0&&str[temp_i]==temp_match){
str[temp_i]=-1;
temp_i++;
if(temp_i==max+1)break;
}
temp_match=str[newInterval[0]];
temp_i=newInterval[0];
while(temp_match!=0&&str[temp_i]==temp_match){
str[temp_i]=-1;
temp_i--;
if(temp_i==-1)break;
}
for(i=newInterval[0];i<=newInterval[1];i++)
str[i]=-1;
boolean catch_left=false;
List<Integer> list=new ArrayList<Integer>();
int count=0;
int last_number=-2;
for(i=min;i<=max;i++){
if(!catch_left&&str[i]!=last_number&&str[i]!=0){
list.add(i);
last_number=str[i];
catch_left=true;
}
else if((catch_left&&str[i]!=last_number)||(i==max&&str[i]!=0)){
if(i!=max){
catch_left=false;
list.add(i-1);
i--;
}else
list.add(i);
count++;
}
}
int[][] result=new int[count][2];
count=0;
for(i=0;i<list.size();i=i+2){
result[count][0]=list.get(i);
result[count][1]=list.get(i+1);
count++;
}
return result;
}
}
连我都觉得自己的代码没法看了,因为一直在根据答案调bug,漏洞太多了,代码补来补去。大致思路是,每个区间在一无限长的线段上都有自己特定的值,添加新的区间后,最后来计算该线段上不同值的区间范围,但一个2147483647把我给整懵了,这方法也算是废了。不过,需要考虑各种各样的情形的算法,检测到一半就该抛弃了,太就题论题了,而且也称不上算法,if,else到处都是。学习一下别人的方法吧。说实话,下面的代码才叫算法嘛。。。。在看看自己的,,,,代码习惯马上改!!!
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
int len = intervals.length;
int[][] res = new int[len + 1][2];
System.arraycopy(intervals, 0, res, 0, len);
res[len] = newInterval;
int[][] ans = new int[len + 1][2];
int index = -1;
Arrays.sort(res, (o1, o2) -> (o1[0] - o2[0]));
for(int[] re: res){
if(index == -1 || re[0] > ans[index][1]){
ans[++index] = re;
}else{
ans[index][1] = Math.max(re[1], ans[index][1]);
}
}
return Arrays.copyOf(ans, index + 1);
}
}
class Solution {
public int jobScheduling(int[] startTime, int[] endTime, int[] profit) {
List<List<Integer>> IList=new ArrayList<List<Integer>>();
int i;
int n=startTime.length;
for(i=0;i<n;i++){
List<Integer> list=new ArrayList<>();
list.add(startTime[i]);
list.add(endTime[i]);
list.add(profit[i]);
IList.add(list);
}
Collections.sort(IList,(o1,o2)->{
return o1.get(1)-o2.get(1);
});
int[] max_money=new int[n];
max_money[0]=IList.get(0).get(2);
for(i=1;i<n;i++){
int start_time=IList.get(i).get(0);
int j=i-1;
while(j>=0){
if(start_time>=IList.get(j).get(1))
break;
j--;
}
if(j==-1){
int add_nowmoney=IList.get(i).get(2);
int not_nowmoney=max_money[i-1];
max_money[i]=add_nowmoney>not_nowmoney?add_nowmoney:not_nowmoney;
}
else{
int add_nowmoney=(max_money[j]+IList.get(i).get(2));
int not_nowmoney=max_money[i-1];
max_money[i]=add_nowmoney>not_nowmoney?add_nowmoney:not_nowmoney;
}
}
int max=-1;
for(i=0;i<n;i++){
if(max_money[i]>max)
max=max_money[i];
}
return max;
}
}
好久没有体会到这种刷题的成就感了,用简洁的代码和明确的思路来解决一个看似复杂的题,太快乐了!!想这种多决策问题,每个阶段的决策都受前一阶段的影响,自然而然想到动态规划,接下来便是如何将该题一步步转换成动态规划模型了,一定证明自己的猜想。这次代码应该比上次可读性高些了吧。还有,对于复杂的题目,千万不要整体理解题目,不要想有多少个if,要分析步骤。
有点小开心,不只是因为高效的写出了哪题,而是彻底理解了归并排序,平时很多题目都可以用该方法来接,而且我也是在这里吃了很多次亏,通过图形推敲,明白了哪些情况下适合用归并排序,并如何正确的书写归并算法,舒服!!今晚我会写一篇有关归并排序的详解以及其应用的博客,理解大家应该都懂,但重在应用!!!给排序画个圆满句号!每日打卡第十二天,以下图为证