137. Single Number II\393. UTF-8 Validation\547. Friend Circles

本文介绍了三个经典算法问题的解决方案:找出数组中仅出现一次的数字、验证UTF-8编码的有效性以及计算社交圈的数量。通过详细解析算法思路与实现代码,为读者提供了深入理解这些问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

137. Single Number II

DESCRIPTION

Given an array of integers, every element appears three times except for one, which appears exactly once. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Here I find the real difference between three times number and once number is the times appear for every digit. If there is no once element, then appearance of every digit 1 is times of 3. But with once element, there exists redundant digits.

IMPLEMENTATION

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int len = nums.size();
        int res = 0;
        if(!len) return res;
        vector<int> rec(32, 0);
        for(auto ele:nums) {
            for(int idx = 0; idx < 32; idx++)
                rec[idx] += (ele & (1 << idx)) != 0;
        }
        for(int idx = 0; idx < 32; idx++) 
            if(rec[idx]%3) 
                res |= (1 << idx);
        return res;        
    }
};

393. UTF-8 Validation

DESCRIPTION

A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules:

For 1-byte character, the first bit is a 0, followed by its unicode code.
For n-bytes character, the first n-bits are all one’s, the n+1 bit is 0, followed by n-1 bytes with most significant 2 bits being 10.
This is how the UTF-8 encoding would work:

   Char. number range  |        UTF-8 octet sequence
      (hexadecimal)    |              (binary)
   --------------------+---------------------------------------------
   0000 0000-0000 007F | 0xxxxxxx
   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Given an array of integers representing the data, return whether it is a valid utf-8 encoding.

Note:
The input is an array of integers. Only the least significant 8 bits of each integer is used to store the data. This means each integer represents only 1 byte of data.

Example 1:


data = [197, 130, 1], which represents the octet sequence: 11000101 10000010 00000001.

Return true.
It is a valid utf-8 encoding for a 2-bytes character followed by a 1-byte character.
Example 2:

data = [235, 140, 4], which represented the octet sequence: 11101011 10001100 00000100.

Return false.
The first 3 bits are all one's and the 4th bit is 0 means it is a 3-bytes character.
The next byte is a continuation byte which starts with 10 and that's correct.
But the second continuation byte does not start with 10, so it is invalid.

From above description, we know that the input is a vector and which element in the vector is regarded as one decoded byte in UTF-8 number.

So my algorithm shows below:

1 go through the whole vector
1.1 get the first byte of the UTF-8 decoded number and calculate the sequential 1s in the first byte.
1.2 if the num_byte is less than 0 or larger than 4 or larger than 256 or smaller than 0 , return false; otherwise, go through num elements in the vector.
1.3 verify the num elements is satisfied with the condition or not. If not, return false; otherwise continue to go.
2 return true.

IMPLEMENTATION

My code shows below with computation complexity O(n2) , and the space complexity is O(1)

class Solution {
public:
    bool validUtf8(vector<int>& data) {
        int num = data.size();
        if(num <= 0) return false;
        int num_byte = 0;
        for(int idx = 0; idx < num;) {
            int fst_byte = data[idx];
            num_byte = 0;
            if(fst_byte > 256 || fst_byte < 0) return false; 
            for(int idx = 7; idx >= 0; idx--) { 
                if((fst_byte & (1 << idx))!=0)
                    num_byte++;
                else 
                    break;
            }   

            if(!num_byte) {
                idx++;
                continue;
            }
            else if(num_byte == 1 || num_byte > 4) return false;
            cout << num_byte << endl;        
            int idx_tail = idx + num_byte;
            if(idx_tail > num) return false;
            for(idx = idx + 1; idx < idx_tail; idx++)
                if(data[idx] > 256 || data[idx] < 0 || ((data[idx] >> 6) != 2))
                    return false;
        }        
        return true;    
    }
};

I change the code to a more concise version according to [1]

class Solution {
public:
    bool validUtf8(vector<int>& data) {
        int num = data.size();
        if(num <= 0) return false;
        int cnt = 0;
        for(auto ele:data) {
            if(!cnt) {
                if(!(ele >> 7))   continue;
                else if((ele >> 5) == 0b110) cnt = 1;
                else if((ele >> 4) == 0b1110) cnt = 2;
                else if((ele >> 3) == 0b11110) cnt = 3;
                else return false;
            }
            else {
                if((ele >> 6) != 0b10) return false;
                cnt--;
            }
        }

        return !cnt;    
    }
};

547. Friend Circles

DESCRIPTION

There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends.

Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jth students are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students.

Example 1:
Input: 
[[1,1,0],
 [1,1,0],
 [0,0,1]]
Output: 2
Explanation:The 0th and 1st students are direct friends, so they are in a friend circle. 
The 2nd student himself is in a friend circle. So return 2.
Example 2:
Input: 
[[1,1,0],
 [1,1,1],
 [0,1,1]]
Output: 1
Explanation:The 0th and 1st students are direct friends, the 1st and 2nd students are direct friends, 
so the 0th and 2nd students are indirect friends. All of them are in the same friend circle, so return 1.
Note:
N is in range [1,200].
M[i][i] = 1 for all students.
If M[i][j] = 1, then M[j][i] = 1.

IMPLEMENTATION

This problem is described as below:

We visit every node in the matrix and do BFS in the node which is not visited before.

So the whole algorithm can be written as:

1 go through the node in the vector which is not visited before
1.1 push the nearest visited node into queue.
1.2 pop the top from queue and and visited its friends until the queue is empty.
1.3 add increament to result.
2 return num_circle

The code shown below:

class Solution {
public:
    int isVisitedAll(vector<bool> & waiting, int dim) {
        for(int idx = 0; idx < dim; idx++)
            if(!waiting[idx]) {
                waiting[idx] = true;
                return idx;
            }    
        return dim;        
    }

    int findCircleNum(vector<vector<int>>& M) {
        int num_circle = 0;
        int dim = M.size();
        vector<bool> waiting_list(dim, false);
        int next_mem = 0;
        while((next_mem = isVisitedAll(waiting_list, dim)) != dim) {
            queue<int> cur_que;
            cur_que.push(next_mem);
            while(!cur_que.empty()) {
                int tp = cur_que.front();
                cur_que.pop();
                M[tp][tp] = 0;
                for(int idx = 0; idx < dim; idx++) {
                    if(M[tp][idx] && !waiting_list[idx]) {
                        cur_que.push(idx);
                        waiting_list[idx] = true;
                    }    
                }
            }
            num_circle++;
        }    
        return num_circle;
    }
};

Ref Link:
[1] UTF-8 Validation: https://discuss.leetcode.com/topic/57195/concise-c-implementation/2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值