算法训练第一周

在这里插入图片描述

NO.1
** LeetCode-283(移动零)**

题目相关描述请点链接

基础写法:

class Solution {
	public void moveZeroes(int[] nums) {
		if(nums==null) {
			return;
		}
		//设置指针i j
		//遍历nums[i] 当nums[i]!=0 即当值不为0时 nums[j]=nums[i];j++;
		int j = 0;
		for(int i=0;i<nums.length;++i) {
			if(nums[i]!=0) {
				nums[j++] = nums[i];
			}
		}
		//可以使i j指针同时向右移 只有当nums[i]!=0 j才移动 造成j指针是慢的一方 所有0遍历完后 数组中>j&&<nums.length的全放0即可
		for(int i=j;i<nums.length;++i) {
			nums[i] = 0;
		}
	}
}	



优化

class Solution {
    public void moveZeroes(int[] nums) {
        if (nums == null || nums.length == 0) {
            return;
        }
        //优化之处在于只进行一次循环,边循环的同时移动i j指针 当数非0时赋给nums[j]
        int j = 0;
        for (int i = 0; i < nums.length; i ++){
            //nums[i]==0 时不需要进行操作  即指针j不需要移动 造成j为慢指针
            
            if (nums[i] != 0) {
           
                if (i != j) { //将数值只有一个元素时的情况考虑进去
                    nums[j] = nums[i];
                    nums[i] = 0;
                }
                j ++;
            }
        }
    }
}





精简

public void moveZeroes(int[] nums) {
    if (nums == null || nums.length == 0) return;        

    int insertPos = 0;//慢指针
    for (int num: nums) {
        if (num != 0) nums[insertPos++] = num;
    }        

    while (insertPos < nums.length) {
        nums[insertPos++] = 0;
    }
}

LeetCode-11(盛最多水的容器)

class Solution {
    public int maxArea(int[] height) {
    //主题思路:利用左右指针 小的一方移动 迭代计算出最大体积
        int l=0,r=height.length-1;
        int ans=0;
        while(l<r){
        //短板效应 面积是底(r-l) 高是左右指针对应数值较小的一方
            int area=Math.min(height[l],height[r])*(r-l);
            //每次计算记录最优值
            ans=Math.max(ans,area);

            if(height[l]<height[r])
            {
                ++l;
            }else{
                --r;
            }
        }
return ans;
    }
}

LeetCode-70(爬楼梯)

class Solution {
//题目抽象出为斐波拉数列模型 f(n)=f(n-1)+f(n-2)
    public int climbStairs(int n) {
       if(n==0||n==1||n==2){
           return n;
       }
       int [] a=new int[n+1];
       a[0]=0;
       a[1]=1;
       a[2]=2;
       for(int i=3;i<=n;i++){
           a[i]=a[i-1]+a[i-2];
       }
           return a[n];
    }
}

LeetCode-1(两数之和)

class Solution {
    public int[] twoSum(int[] nums, int target) {
    //巧妙利用哈希的一键对应一值
            Map<Integer,Integer> map =new HashMap<>();
            for(int i=0;i<nums.length;i++){
                int  a=target-nums[i];
                //两数之和=target 反过来即是target-一方=另一方
                if(map.containsKey(a)){
                //map中的containsKey(key)方法是判断该key在map中是否有key存在。如果存在则返回true。如果不存在则返回false。
                    return new int []{map.get(a),i};

                }
                map.put(nums[i],i);
            }
            throw new IllegalArgumentException("No two sum solution");
    }
}

LeetCode-15(三数之和)

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);//排序处理 复杂度logn
        List<List<Integer>> res = new ArrayList<>();
        for(int k = 0; k < nums.length - 2; k++){//-2是为了留位置给i j双指针
            if(nums[k] > 0) break;//k是固定在最左边的指针 排序后nums[k]最小>0显然不符合
            if(k > 0 && nums[k] == nums[k - 1]) continue;//target值nums[k]如果等于上一次的值 那么已经得过正解 跳过此次循环
            int i = k + 1, j = nums.length - 1;
            while(i < j){
                int sum = nums[k] + nums[i] + nums[j];
                if(sum < 0){//sum<0意味着值为负 左指针需要右移增大数值
                    while(i < j && nums[i] == nums[++i]);
                } else if (sum > 0) {//sum>0意味着值为正 右指针需要左移减小数值
                    while(i < j && nums[j] == nums[--j]);
                } else {
                    res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
                    while(i < j && nums[i] == nums[++i]);
                    while(i < j && nums[j] == nums[--j]);
                }
            }
        }
        return res;
    }
}


在这里插入图片描述


LeetCode-66(加一)

class Solution {
    public int[] plusOne(int[] digits) {
     //最后一个数+1 当需要进位时则循环向前+1 
     //直到digits[i]!=0 返回数组
     for(int i=digits.length-1;i>=0;i--){
         digits[i]++;
         digits[i]=digits[i]%10;
         if(digits[i]!=0) return digits;

     }
     //特殊情况 例如当digits[]=9999
     //则需要手动再扩大数组 将digits[0]=1
     digits=new int [digits.length+1];
     digits[0]=1;
     return digits;
    }
}

LeetCode-24(两两交换链表中的结点)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
       if((head==null)||(head.next==null)){
           return head;
       }
       //创建两个中间结点 
       ListNode first=head;
       ListNode second=head.next;
       //交换过后first.next=second.next
       first.next=swapPairs(second.next);
       //而second.next指向first
       second.next=first;
       
       return second;


    }
}

在这里插入图片描述

旋转数组

class Solution {
    public void rotate(int[] nums, int k) {
        k=k%nums.length;
        //巧妙利用反转
        reserve(nums,0,nums.length-1);//整体反转
        reserve(nums,0,k-1);//反转前K个
        reserve(nums,k,nums.length-1);//反转后半段
        
        


    }
    public void reserve(int[] nums,int start,int end){
        while(start<end){//不停反转从start到end的数
            int temp;
            temp=nums[start];
            nums[start]=nums[end];
            nums[end]=temp;
            start++;
            end--;
        }
    }
}

合并两个有序链表

//递归
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null){
            return l2;
        }else if(l2==null){
            return l1;
        }else if(l1.val<l2.val){//当链表l1的值小于链表l2 则移动链表l1
            l1.next=mergeTwoLists(l1.next,l2);
            return l1;
        }else{
            l2.next=mergeTwoLists(l1,l2.next);
            return l2;
        }
        
    }
}
//迭代
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode prehead=new ListNode(-1);//维护一个节点

        ListNode prev=prehead;
        while(l1!=null&&l2!=null){
        //当两个链表不为空 则依次比较其中节点的大小
            if(l1.val<l2.val){//当l1链表小 则将维护的链表指向l1,且l1往后移
                prev.next=l1;
                l1=l1.next;
            }else{
                prev.next=l2;
                l2=l2.next;
            }
            prev=prev.next;//没获取一次 移动一次
        }
        prev.next=l1==null? l2:l1;
        return prehead.next;
        
    }
}

合并两个有序数组

class Solution {
//双指针 从后往前
    public void merge(int[] nums1, int m, int[] nums2, int n) {
         // 三指针 指针一p1、nums1有效元素尾部;指针二p2、nums2尾部;指针三p3、最终数组尾部
        // 当,p1>=0时,nums[p1],nums[p2]对比
        int p1=m-1,p2=n-1,p3=m+n-1;
        while(p2 >= 0){//因为是将nums2合并到nums1中 ,所以结束条件是p2--到零
            if(p1 >= 0 && nums1[p1] > nums2[p2]){
                nums1[p3--] = nums1[p1--];//nums[p1]大,将nums[p1]放入p3位置。p1--,p3--
            } else {
                nums1[p3--] = nums2[p2--];
                //nums[p2]大于等于nums[p1],将nums[p2]放入p3位置。p2--,p3--
                //当,p1<0时,将nums[p2]放入p3位置。p2--,p3--
            }
    }
}
}

接雨水

//1.按列求
class Solution {
    public int trap(int[] height) {

    int sum = 0;
    //最两端的列不用考虑,因为一定不会有水。所以下标从 1 到 length - 2
    for (int i = 1; i < height.length - 1; i++) {
        int max_left = 0;
        //找出左边最高
        for (int j = i - 1; j >= 0; j--) {
            if (height[j] > max_left) {
                max_left = height[j];
            }
        }
        int max_right = 0;
        //找出右边最高
        for (int j = i + 1; j < height.length; j++) {
            if (height[j] > max_right) {
                max_right = height[j];
            }
        }
        //找出两端较小的
        int min = Math.min(max_left, max_right);
        //只有较小的一段大于当前列的高度才会有水,其他情况不会有水
        if (min > height[i]) {
            sum = sum + (min - height[i]);
        }
    }
    return sum;
}
}


//2.双指针
class Solution {
    public int trap(int[] height) {
        int left=0,right=height.length-1;
        int ans=0;
        int left_max=0,right_max=0;
        while(left<right){
        //当左柱子小于右柱子更新左边 当右柱子小于左柱子更新右边
            if(height[left]<height[right]){
            //当柱子大于左边记录的最大值则覆盖 小于最大值则有积水
                if(height[left]>=left_max){
                    left_max=height[left];
                }else{
                    ans+=(left_max-height[left]);
                }
                ++left;
            }else{
            //当柱子大于右边记录的最大值覆盖 小于最大值则有积水
                if(height[right]>=right_max){
                    right_max=height[right];
                }else{
                    ans+=(right_max-height[right]);
                }
                --right;
            }
        }
        return ans;
    }
}

学习总结:
1.牢记过遍数的重要性,每日跟进学习刷题。
2.刷题时重点掌握最好的题解,多学习其他人的优秀代码,开阔自己的思维。
3.认真且自主的学习讲义所有内容,学会分析源代码。
4.学习的情况不是很理想,观看学习视频时不够集中,每日安排的时间质量不够好。还没有掌握自己的思维模式,需要学习更加优秀的总结方法。

(此文章为自己学习记录 没有详细的思路讲解)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值