每日算法(2021/9/24)

从今天开始每日算法,目的是熟悉语言语法结构,也为了能够提高自己的编码能力,会用多种语言,当然逻辑相通。

平台基于leetcode平台,会从基础开始,每天3简单,2中等,1困难。(之后会提量,现在做的比较慢,第一天做了五道简单练手,后面会回到正常)

不知道能保持多久,总之尽量。

会给出题目名称,不给出内容只给题解。

以下。

1.Tow Sum(两数之和)简单

看到这道题,第一时间想到的当然是遍历,那么为了能够高速遍历我们就需要用到哈希表(哈希为什么告诉请自行查询,总来说是因为能够指向性直接读取内存)。

java:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map = new HashMap();//创建哈希表
        for(int i=0;i<nums.length;i++ )//遍历nums内的数据
        {
            if(map.containsKey(target-nums[i]))//判断是否存在两数之和等于terget,利用的是key值的查找
                return new int[] {map.get(target-nums[i]),i};//存在则返回,不存在加入map继续遍历
            map.put(nums[i],i);
        }
        throw new IllegalArgumentException("No Two Sum Solution");//抛出异常
    }
}

速度也是非常的快(后面那个抛异常是看的题解23333)。

2.Reverse Integer(整数反转)简单

java:

class Solution {
    public int reverse(int x) {
        int res = 0;//存储结论数
        while(x!=0){//考虑循环取模后相加
            int tmp = x%10;//循环取模。本题核心
            if(res>214748364 || (res==214748364 && tmp>7))//范围判断
                return 0;
            if(res<-214748364 || (res==-214748364 && tmp<-8))//一开始这两个判断写在了一起,后来想了想第一个判断语句与后一句有关,大量判断明显是无效的,所以分开可以降低平均数。
                return 0;
            x=x/10;
            res = tmp+res*10;
        }
        return res;
    }
}

第一次提交没算res,有笑到自己。

3.Palindrome Number(回文数)简单

第一反应最简单的是通过指针,将数据打散放入数组,指针前后挨个对照。

缺点明显,占用空间大,效率低。

观察回文数特征,后一半的数反向排列与前一半数相同,那么我们可以挨个取出来,乘以相应倍率,然后和前一半对比(假设是偶数位数),奇数只要前面或者后面进行一个取模再比较即可。

java:

class Solution {
    public boolean isPalindrome(int x) {
        if(x>0&&x<10) return true;//显然是回文
        if (x < 0 || (x % 10 == 0 && x != 0)) return false;//显然不是
        int reverted = 0;
        while (x > reverted) {
            reverted = reverted * 10 + x % 10;
            x /= 10;
        }//进行前后半段对照
        return x == reverted || x == reverted / 10;//该方法的优势在于内存消耗,速率有一定损失但是不大
    }
}

python3:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        return True if str(x) == str(x)[::-1] else False

本来都想用python,但是不知道为什么if语句的退格一直出问题,python自带有字符串反转语句,可以调用。

4.Roman to Integer(罗马数字转整数)简单


class Solution {
    public int romanToInt(String s) {
        int num = getValue(s.charAt(0));
        int xnum =0;
        int x =0;
        for(int i = 1;i < s.length(); i ++) {
            xnum = getValue(s.charAt(i));
            if(num < xnum) {
                x = x - num;
            } else {
                x = x + num;
            }
            num = xnum;
        }
        x = x+ num;
        return x;
    }
    
    private int getValue(char ch) {
        switch(ch) {
            case 'I': return 1;
            case 'V': return 5;
            case 'X': return 10;
            case 'L': return 50;
            case 'C': return 100;
            case 'D': return 500;
            case 'M': return 1000;
            default: return 0;
        }
    }
}

这个没什么可说的,主要是在意一下右边恒正这个问题,我自己做的时候最后没加num导致第一次提交错误hhh。

5.longest common prefix(最长公共前缀)简单

java


class Solution {
    public String longestCommonPrefix(String[] strs) {

    if (strs.length == 0) {
        return "";
    }

    // 最长前缀末尾位置
    int longest = strs[0].length() - 1;

    for (int i = 1; i < strs.length; ++i) {
        int j = 0;
        for (; j <= longest && j < strs[i].length(); ++j) {
            if (strs[0].charAt(j) != strs[i].charAt(j)) {
                break;
            }
        }
        // j 的位置不相同
        longest = Math.min(longest, j - 1);

        // 没有公共前缀, 不用再遍历剩余字符串
        if (longest < 0break;
    }

    return strs[0].substring(0, longest + 1);
}
}
 

近乎是循环遍历的方式。

6.Add Tow Numbers(两数相加)中等

java:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode pre = new ListNode(0);//创建两个“指针”用于定位
        ListNode pre2 = pre;
        int carry = 0;//存放进位
         while(l1 != null || l2 != null)//判断循环是两者皆空
        {
            int x = l1 == null ? 0 : l1.val;//取值
            int y = l2 == null ? 0 : l2.val;//取值
            int sum = x + y + carry;//相加并且获得进位
            carry = sum >9 ? 1 : 0;//判断是否存在进位
            sum = sum % 10;//进位去除

            pre2.next = new ListNode(sum);

            pre2 = pre2.next;
            if(l1 != null)
                l1 = l1.next;
            if(l2 != null)
                l2 = l2.next;
        }
            if(carry == 1) {//判断是否需要加节点
            pre2.next = new ListNode(carry);
        }
        return pre.next;
    }
}

缺点是新建链表了,其实可以直接放在其中一个表中用于节省空间。

 7.Longest Substring Without Repeating Characters(无重复字符的最长字串)中等

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;//总忘记写这个
        HashMap<Character,Integer> map = new HashMap();//题解中有一个称呼为“滑动窗口”我也不知道怎么称呼合适,这个蛮形象的。
        int max = 0;//记录结果
        int left = 0;//记录窗口左边界

        for(int i=0;i<s.length();i++){
            
            if(map.containsKey(s.charAt(i))){//哈希查重
                left = Math.max(left,map.get(s.charAt(i)) + 1);//核心语句,边界移动
            }
            map.put(s.charAt(i),i);
            max = Math.max(max,i-left+1);
        }
        return max;
    }
}

8.Median of Tow Sorted Arrays(两个正序数组的中位数)

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int n = nums1.length;
    int m = nums2.length;

    int left = (n + m + 1) / 2;
    int right = (n + m + 2) / 2;

    return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;  
    }

    
    private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
        int len1 = end1 - start1 + 1;
        int len2 = end2 - start2 + 1;
        if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);
        
        if (len1 == 0) return nums2[start2 + k - 1];

        if (k == 1) return Math.min(nums1[start1], nums2[start2]);

        int i = start1 + Math.min(len1, k / 2) - 1;
        int j = start2 + Math.min(len2, k / 2) - 1;

        if (nums1[i] > nums2[j]) {
            return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
        }
        else {
            return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
        }
    }

}

这里采用了两个数组同切的方式,能够在不开辟新空间的情况下采用二分法进行分割判断。

奇偶合并参考题解,自己脑子没转过来(。

效率还可以,题解有一个法4我没太理解,法3和我这个一样。

本题难点在于如何进行二分法切割,在不开辟新空间的情况下进行大小比对得出中位数,采用了k/2然后对小数删除的筛选思想得到中位数解。

 

2021/9/24总结:

很久没有写算法题了,leetcode是一个不错的平台,首日写了8题用了2-3小时,时长较长。

考虑原因的话,一是没有IDE纠正语法与提示,明显降低了代码效率,很多函数蒙住不会拼写hhhh。

二是算法题很多时间在于题目分析,做题较少的情况下分析速度慢,想要提高代码效率的话还是应该先写下来然后逐步改进,我这里更多想要一步到位,只能一定程度上保证效率。

不过我写算法的目的是能够快速理解算法结构,方便代码审计阅读,也方便自己进行开发,入门路且长。

posted @ 2021-09-24 13:02  HOloBlogs  阅读(77)  评论(0)    收藏  举报